mirror of https://gitlab.com/ngerakines/tavern.git
Added prometheus metrics. Closes #37
This commit is contained in:
parent
50689e5444
commit
d152d5520a
|
@ -5,6 +5,10 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// HTTPClient provides the http.Do function in a generic way.
|
||||
|
@ -20,7 +24,7 @@ type AcceptHeader struct {
|
|||
type AcceptHeaders []AcceptHeader
|
||||
|
||||
// DefaultHTTPClient returns an HTTPClient with a reasonable default timeout.
|
||||
func DefaultHTTPClient() HTTPClient {
|
||||
func DefaultHTTPClient() *http.Client {
|
||||
return &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
|
||||
|
@ -31,6 +35,81 @@ func DefaultHTTPClient() HTTPClient {
|
|||
}
|
||||
}
|
||||
|
||||
func InstrumentedDefaultHTTPClient(metricFactory promauto.Factory) *http.Client {
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
|
||||
// By default, the HTTP client shouldn't follow redirects.
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
inFlightGauge := metricFactory.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "client_in_flight_requests",
|
||||
Help: "A gauge of in-flight requests for the wrapped client.",
|
||||
})
|
||||
|
||||
counter := metricFactory.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "client_api_requests_total",
|
||||
Help: "A counter for requests from the wrapped client.",
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
|
||||
dnsLatencyVec := metricFactory.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "dns_duration_seconds",
|
||||
Help: "Trace dns latency histogram.",
|
||||
Buckets: []float64{.005, .01, .025, .05},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
tlsLatencyVec := metricFactory.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "tls_duration_seconds",
|
||||
Help: "Trace tls latency histogram.",
|
||||
Buckets: []float64{.05, .1, .25, .5},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
histVec := metricFactory.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "request_duration_seconds",
|
||||
Help: "A histogram of request latencies.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{"method"},
|
||||
)
|
||||
|
||||
trace := &promhttp.InstrumentTrace{
|
||||
DNSStart: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_start").Observe(t)
|
||||
},
|
||||
DNSDone: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_done").Observe(t)
|
||||
},
|
||||
TLSHandshakeStart: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_start").Observe(t)
|
||||
},
|
||||
TLSHandshakeDone: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_done").Observe(t)
|
||||
},
|
||||
}
|
||||
|
||||
client.Transport = promhttp.InstrumentRoundTripperInFlight(inFlightGauge,
|
||||
promhttp.InstrumentRoundTripperCounter(counter,
|
||||
promhttp.InstrumentRoundTripperTrace(trace,
|
||||
promhttp.InstrumentRoundTripperDuration(histVec, http.DefaultTransport),
|
||||
),
|
||||
),
|
||||
)
|
||||
return client
|
||||
}
|
||||
|
||||
func ParseAccept(input string) AcceptHeaders {
|
||||
// From the spec, https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
// If no Accept header field is present, then it is assumed that the client
|
||||
|
@ -105,3 +184,8 @@ func (a AcceptHeaders) MatchJRD(exact bool) bool {
|
|||
_, _, m := a.Match(exact, "application/json")
|
||||
return m
|
||||
}
|
||||
|
||||
func (a AcceptHeaders) MatchHTML(exact bool) bool {
|
||||
_, _, m := a.Match(exact, "text/html")
|
||||
return m
|
||||
}
|
||||
|
|
2
go.mod
2
go.mod
|
@ -20,6 +20,7 @@ require (
|
|||
github.com/microcosm-cc/bluemonday v1.0.2
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/oklog/run v1.0.0
|
||||
github.com/prometheus/client_golang v1.5.1
|
||||
github.com/sslhound/herr v1.4.1 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/teacat/noire v1.0.0
|
||||
|
@ -28,6 +29,5 @@ require (
|
|||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20200221170553-0f24fbd83dfb
|
||||
golang.org/x/tools v0.0.0-20200228224639-71482053b885 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.7 // indirect
|
||||
)
|
||||
|
|
25
go.sum
25
go.sum
|
@ -39,12 +39,17 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
|
|||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
|
@ -54,6 +59,8 @@ github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414
|
|||
github.com/buckket/go-blurhash v1.0.3 h1:zCSPYlKYWxF+3I/JJT2GrF4ut6wRaifz89JdsdZClpw=
|
||||
github.com/buckket/go-blurhash v1.0.3/go.mod h1:BUt9nlD6V+23blJqm6Vn/423xpTnP1OLA9yv+y4l44U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -125,7 +132,9 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
|
|||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
|
@ -221,6 +230,7 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB
|
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
|
@ -271,6 +281,7 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
|
|||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
|
||||
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
|
||||
|
@ -319,12 +330,24 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
|
||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
|
@ -464,6 +487,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
|
@ -620,6 +644,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
|
|
|
@ -2,6 +2,7 @@ package job
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
@ -24,13 +25,13 @@ type assetDownload struct {
|
|||
fedConfig config.FedConfig
|
||||
}
|
||||
|
||||
func NewAssetDownloadJob(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, assetStorage asset.Storage, config config.AssetStorageConfig, fedConfig config.FedConfig) Job {
|
||||
func NewAssetDownloadJob(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, assetStorage asset.Storage, config config.AssetStorageConfig, fedConfig config.FedConfig, httpClient *http.Client) Job {
|
||||
return &assetDownload{
|
||||
logger: logger,
|
||||
queue: queue,
|
||||
storage: storage,
|
||||
assetStorage: assetStorage,
|
||||
httpClient: common.DefaultHTTPClient(),
|
||||
httpClient: httpClient,
|
||||
assetStorageConfig: config,
|
||||
fedConfig: fedConfig,
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package job
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -28,13 +29,13 @@ type crawl struct {
|
|||
fedConfig config.FedConfig
|
||||
}
|
||||
|
||||
func NewCrawlWorker(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, assetStorage asset.Storage, config config.AssetStorageConfig, fedConfig config.FedConfig) Job {
|
||||
func NewCrawlWorker(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, assetStorage asset.Storage, config config.AssetStorageConfig, fedConfig config.FedConfig, httpClient *http.Client) Job {
|
||||
return &crawl{
|
||||
logger: logger,
|
||||
queue: queue,
|
||||
storage: storage,
|
||||
assetStorage: assetStorage,
|
||||
httpClient: common.DefaultHTTPClient(),
|
||||
httpClient: httpClient,
|
||||
assetStorageConfig: config,
|
||||
fedConfig: fedConfig,
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package job
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
@ -22,12 +23,12 @@ type webfinger struct {
|
|||
fedConfig config.FedConfig
|
||||
}
|
||||
|
||||
func NewWebFingerWorker(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, fedConfig config.FedConfig) Job {
|
||||
func NewWebFingerWorker(logger *zap.Logger, queue common.StringQueue, storage storage.Storage, fedConfig config.FedConfig, httpClient *http.Client) Job {
|
||||
return &webfinger{
|
||||
logger: logger,
|
||||
queue: queue,
|
||||
storage: storage,
|
||||
httpClient: common.DefaultHTTPClient(),
|
||||
httpClient: httpClient,
|
||||
fedConfig: fedConfig,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/oklog/run"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
|
||||
|
@ -203,9 +206,16 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
crawlQueue := common.NewStringQueue()
|
||||
assetQueue := common.NewStringQueue()
|
||||
|
||||
registry := prometheus.NewRegistry()
|
||||
if err = registry.Register(prometheus.NewGoCollector()); err != nil {
|
||||
return err
|
||||
}
|
||||
fact := promauto.With(registry)
|
||||
httpClient :=common.InstrumentedDefaultHTTPClient(fact)
|
||||
|
||||
var svgConv SVGConverter
|
||||
if svgerConfig.Enabled {
|
||||
svgConv = DefaultSVGerClient(svgerConfig.Location)
|
||||
svgConv = DefaultSVGerClient(svgerConfig.Location, httpClient)
|
||||
}
|
||||
|
||||
h := handler{
|
||||
|
@ -221,10 +231,30 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
url: tmplUrlGen(siteBase),
|
||||
svgConverter: svgConv,
|
||||
assetStorage: assetStorage,
|
||||
httpClient: httpClient,
|
||||
metricFactory: promauto.With(registry),
|
||||
}
|
||||
|
||||
configI18nMiddleware(sentryConfig, logger, utrans, domain, r)
|
||||
|
||||
mm := newMetricsMiddleware("tavern", promauto.With(registry))
|
||||
|
||||
r.Use(func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
c.Next()
|
||||
|
||||
status := fmt.Sprintf("%d", c.Writer.Status())
|
||||
endpoint := c.FullPath()
|
||||
method := c.Request.Method
|
||||
|
||||
lvs := []string{status, endpoint, method}
|
||||
|
||||
mm.requests.WithLabelValues(lvs...).Inc()
|
||||
mm.totalTime.WithLabelValues(lvs...).Observe(time.Since(start).Seconds())
|
||||
mm.requestSize.WithLabelValues(lvs...).Observe(calcRequestSize(c.Request))
|
||||
mm.responseSize.WithLabelValues(lvs...).Observe(float64(c.Writer.Size()))
|
||||
})
|
||||
|
||||
root := r.Group("/")
|
||||
{
|
||||
root.GET("/.well-known/webfinger", h.webFinger)
|
||||
|
@ -242,6 +272,13 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
root.GET("/asset/thumbnail/:checksum", h.viewThumbnail)
|
||||
root.GET("/asset/blurhash/:blurHash", h.viewBlur)
|
||||
|
||||
promhandler := promhttp.InstrumentMetricHandler(
|
||||
registry, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}),
|
||||
)
|
||||
root.GET("/metrics", func(c *gin.Context) {
|
||||
promhandler.ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
root.GET("/avatar/svg/:domain/:name", h.avatarSVG)
|
||||
if svgerConfig.Enabled {
|
||||
root.GET("/avatar/png/:domain/:name", h.avatarPNG)
|
||||
|
@ -316,13 +353,13 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
}
|
||||
})
|
||||
|
||||
webFingerJob := job.NewWebFingerWorker(logger, webFingerQueue, s, fedConfig)
|
||||
webFingerJob := job.NewWebFingerWorker(logger, webFingerQueue, s, fedConfig, httpClient)
|
||||
job.RunWorker(&group, logger, webFingerJob, parentCtx)
|
||||
|
||||
crawlJob := job.NewCrawlWorker(logger, crawlQueue, s, assetStorage, assetStorageConfig, fedConfig)
|
||||
crawlJob := job.NewCrawlWorker(logger, crawlQueue, s, assetStorage, assetStorageConfig, fedConfig, httpClient)
|
||||
job.RunWorker(&group, logger, crawlJob, parentCtx)
|
||||
|
||||
assetJob := job.NewAssetDownloadJob(logger, assetQueue, s, assetStorage, assetStorageConfig, fedConfig)
|
||||
assetJob := job.NewAssetDownloadJob(logger, assetQueue, s, assetStorage, assetStorageConfig, fedConfig, httpClient)
|
||||
job.RunWorker(&group, logger, assetJob, parentCtx)
|
||||
|
||||
quit := make(chan os.Signal)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/getsentry/sentry-go"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/asset"
|
||||
|
@ -30,6 +31,9 @@ type handler struct {
|
|||
assetStorage asset.Storage
|
||||
assetQueue common.StringQueue
|
||||
fedConfig config.FedConfig
|
||||
|
||||
httpClient common.HTTPClient
|
||||
metricFactory promauto.Factory
|
||||
}
|
||||
|
||||
func (h handler) hardFail(ctx *gin.Context, err error, fields ...zap.Field) {
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
func (h handler) actorInfo(c *gin.Context) {
|
||||
accepted := common.ParseAccept(c.GetHeader("Accept"))
|
||||
if _, _, ok := accepted.Match(true, "text/html"); ok {
|
||||
if accepted.MatchHTML(true) {
|
||||
h.viewUser(c)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/yukimochi/httpsig"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
|
@ -190,7 +189,7 @@ func (h handler) actorInboxFollow(c *gin.Context, user *storage.User, payload st
|
|||
return
|
||||
}
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), target)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, target)
|
||||
if err != nil {
|
||||
h.internalServerErrorJSON(c, err)
|
||||
return
|
||||
|
@ -227,7 +226,7 @@ func (h handler) actorInboxFollow(c *gin.Context, user *storage.User, payload st
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, h.userActor(user, userActor), followerActor, responsePayload)
|
||||
|
@ -478,7 +477,7 @@ func (h handler) actorInboxAnnounce(c *gin.Context, user *storage.User, payload
|
|||
}
|
||||
|
||||
ac := fed.ActivityClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
if _, ok := mentionedActors[mentionedActor]; ok {
|
||||
continue
|
||||
}
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), mentionedActor)
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, mentionedActor)
|
||||
if err == nil {
|
||||
mentionedActors[mentionedActor] = foundActor
|
||||
to = append(to, foundActor.ActorID)
|
||||
|
@ -427,14 +427,14 @@ func (h handler) createNote(c *gin.Context) {
|
|||
}
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
localActor := h.userActor(user, userActor)
|
||||
|
||||
if broadcastTo {
|
||||
for _, dest := range toDestinations {
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), dest)
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, dest)
|
||||
if err != nil {
|
||||
h.logger.Error("unable to get or fetch actor", zap.Error(err), zap.String("actor", dest))
|
||||
continue
|
||||
|
@ -448,7 +448,7 @@ func (h handler) createNote(c *gin.Context) {
|
|||
|
||||
if broadcastCC {
|
||||
for _, dest := range ccDestinations {
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), dest)
|
||||
foundActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, dest)
|
||||
if err != nil {
|
||||
h.logger.Error("unable to get or fetch actor", zap.Error(err), zap.String("actor", dest))
|
||||
continue
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ngerakines/tavern/common"
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
"github.com/ngerakines/tavern/fed"
|
||||
"github.com/ngerakines/tavern/storage"
|
||||
|
@ -116,7 +115,7 @@ func (h handler) networkFollow(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), c.PostForm("actor"))
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, c.PostForm("actor"))
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, h.url("network"), err)
|
||||
return
|
||||
|
@ -143,7 +142,7 @@ func (h handler) networkFollow(c *gin.Context) {
|
|||
payload := follow.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, h.userActor(user, userActor), actor, payload)
|
||||
|
@ -186,7 +185,7 @@ func (h handler) networkUnfollow(c *gin.Context) {
|
|||
}
|
||||
|
||||
target := c.PostForm("actor")
|
||||
targetActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), target)
|
||||
targetActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, target)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, h.url("network"), err)
|
||||
return
|
||||
|
@ -217,7 +216,7 @@ func (h handler) networkUnfollow(c *gin.Context) {
|
|||
|
||||
payload := undoFollow.Bytes()
|
||||
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), to)
|
||||
actor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, to)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, h.url("network"), err)
|
||||
return
|
||||
|
@ -230,7 +229,7 @@ func (h handler) networkUnfollow(c *gin.Context) {
|
|||
}
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, h.userActor(user, userActor), actor, payload)
|
||||
|
@ -269,7 +268,7 @@ func (h handler) networkAccept(c *gin.Context) {
|
|||
|
||||
targetActorID := c.PostForm("actor")
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), targetActorID)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, targetActorID)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, h.url("network"), err)
|
||||
return
|
||||
|
@ -292,7 +291,7 @@ func (h handler) networkAccept(c *gin.Context) {
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, h.userActor(user, userActor), followerActor, responsePayload)
|
||||
|
@ -337,7 +336,7 @@ func (h handler) networkReject(c *gin.Context) {
|
|||
|
||||
targetActorID := c.PostForm("actor")
|
||||
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, common.DefaultHTTPClient(), targetActorID)
|
||||
followerActor, err := fed.GetOrFetchActor(ctx, h.storage, h.logger, h.httpClient, targetActorID)
|
||||
if err != nil {
|
||||
h.flashErrorOrFail(c, h.url("network"), err)
|
||||
return
|
||||
|
@ -360,7 +359,7 @@ func (h handler) networkReject(c *gin.Context) {
|
|||
responsePayload := response.Bytes()
|
||||
|
||||
nc := fed.ActorClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: h.httpClient,
|
||||
Logger: h.logger,
|
||||
}
|
||||
err = nc.SendToInbox(ctx, h.userActor(user, userActor), followerActor, responsePayload)
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
func (h handler) getObject(c *gin.Context) {
|
||||
accepted := common.ParseAccept(c.GetHeader("Accept"))
|
||||
if _, _, ok := accepted.Match(true, "text/html"); ok {
|
||||
if accepted.MatchHTML(true) {
|
||||
h.viewObject(c)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
)
|
||||
|
||||
type metricsMiddleware struct {
|
||||
requests *prometheus.CounterVec
|
||||
totalTime *prometheus.HistogramVec
|
||||
requestSize *prometheus.SummaryVec
|
||||
responseSize *prometheus.SummaryVec
|
||||
}
|
||||
|
||||
func newMetricsMiddleware(namespace string, metricFactory promauto.Factory) metricsMiddleware {
|
||||
return metricsMiddleware{
|
||||
requests: metricFactory.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Name: "http_request_count_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
}, []string{"status", "endpoint", "method"},
|
||||
),
|
||||
totalTime: metricFactory.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Name: "http_request_duration_seconds",
|
||||
Help: "HTTP request latencies in seconds.",
|
||||
}, []string{"status", "endpoint", "method"},
|
||||
),
|
||||
requestSize: metricFactory.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Namespace: namespace,
|
||||
Name: "http_request_size_bytes",
|
||||
Help: "HTTP request sizes in bytes.",
|
||||
}, []string{"status", "endpoint", "method"},
|
||||
),
|
||||
responseSize: metricFactory.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Namespace: namespace,
|
||||
Name: "http_response_size_bytes",
|
||||
Help: "HTTP request sizes in bytes.",
|
||||
}, []string{"status", "endpoint", "method"},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// calcRequestSize returns the size of request object.
|
||||
func calcRequestSize(r *http.Request) float64 {
|
||||
size := 0
|
||||
if r.URL != nil {
|
||||
size = len(r.URL.String())
|
||||
}
|
||||
|
||||
size += len(r.Method)
|
||||
size += len(r.Proto)
|
||||
|
||||
for name, values := range r.Header {
|
||||
size += len(name)
|
||||
for _, value := range values {
|
||||
size += len(value)
|
||||
}
|
||||
}
|
||||
size += len(r.Host)
|
||||
|
||||
// r.Form and r.MultipartForm are assumed to be included in r.URL.
|
||||
if r.ContentLength != -1 {
|
||||
size += int(r.ContentLength)
|
||||
}
|
||||
return float64(size)
|
||||
}
|
|
@ -20,9 +20,9 @@ type SVGerClient struct {
|
|||
Endpoint string
|
||||
}
|
||||
|
||||
func DefaultSVGerClient(endpoint string) SVGConverter {
|
||||
func DefaultSVGerClient(endpoint string, httpClient common.HTTPClient) SVGConverter {
|
||||
return SVGerClient{
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
HTTPClient: httpClient,
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue