Added prometheus metrics. Closes #37

This commit is contained in:
Nick Gerakines 2020-03-17 20:46:59 -04:00
parent 50689e5444
commit d152d5520a
No known key found for this signature in database
GPG Key ID: 33D43D854F96B2E4
15 changed files with 258 additions and 34 deletions

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}
}

View File

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

View File

@ -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) {

View File

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

View File

@ -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,
}

View File

@ -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

View File

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

View File

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

73
web/metrics.go Normal file
View File

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

View File

@ -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,
}
}