Merge pull request #2547 from pracucci/allow-to-customize-http-client-in-receiver-integrations

Add HTTP client options to receiver integrations
This commit is contained in:
Julien Pivotto 2021-04-22 11:38:09 +02:00 committed by GitHub
commit cb8a467cfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 122 additions and 32 deletions

2
go.mod
View File

@ -23,7 +23,7 @@ require (
github.com/oklog/ulid v1.3.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/common v0.18.0
github.com/prometheus/common v0.21.0
github.com/prometheus/exporter-toolkit v0.5.0
github.com/rs/cors v1.7.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749

4
go.sum
View File

@ -440,8 +440,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.18.0 h1:WCVKW7aL6LEe1uryfI9dnEc2ZqNB1Fn0ok930v0iL1Y=
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.21.0 h1:SMvI2JVldvfUvRVlP64jkIJEC6WiGHJcN2e5tB+ztF8=
github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/exporter-toolkit v0.5.0 h1:GwrxhCviqOl8Mm0vKqkh7Xy54m+FPlHEJacFs48M3gY=
github.com/prometheus/exporter-toolkit v0.5.0/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=

View File

@ -43,8 +43,8 @@ type Notifier struct {
}
// New returns a new OpsGenie notifier.
func New(c *config.OpsGenieConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "opsgenie", false, false)
func New(c *config.OpsGenieConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "opsgenie", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -48,8 +48,8 @@ type Notifier struct {
}
// New returns a new PagerDuty notifier.
func New(c *config.PagerdutyConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "pagerduty", false, false)
func New(c *config.PagerdutyConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "pagerduty", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -42,8 +42,8 @@ type Notifier struct {
}
// New returns a new Pushover notifier.
func New(c *config.PushoverConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "pushover", false, false)
func New(c *config.PushoverConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "pushover", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -42,8 +42,8 @@ type Notifier struct {
}
// New returns a new Slack notification handler.
func New(c *config.SlackConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "slack", false, false)
func New(c *config.SlackConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "slack", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -41,8 +41,8 @@ type Notifier struct {
}
// New returns a new VictorOps notifier.
func New(c *config.VictorOpsConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "victorops", false, false)
func New(c *config.VictorOpsConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "victorops", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -44,8 +44,8 @@ type Notifier struct {
}
// New returns a new Webhook.
func New(conf *config.WebhookConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*conf.HTTPConfig, "webhook", false, false)
func New(conf *config.WebhookConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*conf.HTTPConfig, "webhook", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -71,8 +71,8 @@ type weChatResponse struct {
}
// New returns a new Wechat notifier.
func New(c *config.WechatConfig, t *template.Template, l log.Logger) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "wechat", false, false)
func New(c *config.WechatConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "wechat", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
if err != nil {
return nil, err
}

View File

@ -17,11 +17,13 @@ package config
import (
"bytes"
"crypto/md5"
"context"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
@ -38,6 +40,12 @@ var DefaultHTTPClientConfig = HTTPClientConfig{
FollowRedirects: true,
}
// defaultHTTPClientOptions holds the default HTTP client options.
var defaultHTTPClientOptions = httpClientOptions{
keepAlivesEnabled: true,
http2Enabled: true,
}
type closeIdler interface {
CloseIdleConnections()
}
@ -194,15 +202,50 @@ func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error {
return unmarshal((*plain)(a))
}
// DialContextFunc defines the signature of the DialContext() function implemented
// by net.Dialer.
type DialContextFunc func(context.Context, string, string) (net.Conn, error)
type httpClientOptions struct {
dialContextFunc DialContextFunc
keepAlivesEnabled bool
http2Enabled bool
}
// HTTPClientOption defines an option that can be applied to the HTTP client.
type HTTPClientOption func(options *httpClientOptions)
// WithDialContextFunc allows you to override func gets used for the actual dialing. The default is `net.Dialer.DialContext`.
func WithDialContextFunc(fn DialContextFunc) HTTPClientOption {
return func(opts *httpClientOptions) {
opts.dialContextFunc = fn
}
}
// WithKeepAlivesDisabled allows to disable HTTP keepalive.
func WithKeepAlivesDisabled() HTTPClientOption {
return func(opts *httpClientOptions) {
opts.keepAlivesEnabled = false
}
}
// WithHTTP2Disabled allows to disable HTTP2.
func WithHTTP2Disabled() HTTPClientOption {
return func(opts *httpClientOptions) {
opts.http2Enabled = false
}
}
// NewClient returns a http.Client using the specified http.RoundTripper.
func newClient(rt http.RoundTripper) *http.Client {
return &http.Client{Transport: rt}
}
// NewClientFromConfig returns a new HTTP client configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewClientFromConfig(cfg HTTPClientConfig, name string, disableKeepAlives, enableHTTP2 bool) (*http.Client, error) {
rt, err := NewRoundTripperFromConfig(cfg, name, disableKeepAlives, enableHTTP2)
// given config.HTTPClientConfig and config.HTTPClientOption.
// The name is used as go-conntrack metric label.
func NewClientFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HTTPClientOption) (*http.Client, error) {
rt, err := NewRoundTripperFromConfig(cfg, name, optFuncs...)
if err != nil {
return nil, err
}
@ -216,8 +259,27 @@ func NewClientFromConfig(cfg HTTPClientConfig, name string, disableKeepAlives, e
}
// NewRoundTripperFromConfig returns a new HTTP RoundTripper configured for the
// given config.HTTPClientConfig. The name is used as go-conntrack metric label.
func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, disableKeepAlives, enableHTTP2 bool) (http.RoundTripper, error) {
// given config.HTTPClientConfig and config.HTTPClientOption.
// The name is used as go-conntrack metric label.
func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HTTPClientOption) (http.RoundTripper, error) {
opts := defaultHTTPClientOptions
for _, f := range optFuncs {
f(&opts)
}
var dialContext func(ctx context.Context, network, addr string) (net.Conn, error)
if opts.dialContextFunc != nil {
dialContext = conntrack.NewDialContextFunc(
conntrack.DialWithDialContextFunc((func(context.Context, string, string) (net.Conn, error))(opts.dialContextFunc)),
conntrack.DialWithTracing(),
conntrack.DialWithName(name))
} else {
dialContext = conntrack.NewDialContextFunc(
conntrack.DialWithTracing(),
conntrack.DialWithName(name))
}
newRT := func(tlsConfig *tls.Config) (http.RoundTripper, error) {
// The only timeout we care about is the configured scrape timeout.
// It is applied on request. So we leave out any timings here.
@ -225,7 +287,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, disableKeepAli
Proxy: http.ProxyURL(cfg.ProxyURL.URL),
MaxIdleConns: 20000,
MaxIdleConnsPerHost: 1000, // see https://github.com/golang/go/issues/13801
DisableKeepAlives: disableKeepAlives,
DisableKeepAlives: !opts.keepAlivesEnabled,
TLSClientConfig: tlsConfig,
DisableCompression: true,
// 5 minutes is typically above the maximum sane scrape interval. So we can
@ -233,12 +295,9 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, disableKeepAli
IdleConnTimeout: 5 * time.Minute,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: conntrack.NewDialContextFunc(
conntrack.DialWithTracing(),
conntrack.DialWithName(name),
),
DialContext: dialContext,
}
if enableHTTP2 {
if opts.http2Enabled {
// HTTP/2 support is golang has many problematic cornercases where
// dead connections would be kept and used in connection pools.
// https://github.com/golang/go/issues/32388
@ -533,7 +592,7 @@ func (t *tlsRoundTripper) getCAWithHash() ([]byte, []byte, error) {
if err != nil {
return nil, nil, err
}
h := md5.Sum(b)
h := sha256.Sum256(b)
return b, h[:], nil
}

View File

@ -14,6 +14,8 @@
package model
import (
"encoding/json"
"errors"
"fmt"
"math"
"regexp"
@ -201,13 +203,23 @@ func ParseDuration(durationStr string) (Duration, error) {
// Parse the match at pos `pos` in the regex and use `mult` to turn that
// into ms, then add that value to the total parsed duration.
var overflowErr error
m := func(pos int, mult time.Duration) {
if matches[pos] == "" {
return
}
n, _ := strconv.Atoi(matches[pos])
// Check if the provided duration overflows time.Duration (> ~ 290years).
if n > int((1<<63-1)/mult/time.Millisecond) {
overflowErr = errors.New("duration out of range")
}
d := time.Duration(n) * time.Millisecond
dur += d * mult
if dur < 0 {
overflowErr = errors.New("duration out of range")
}
}
m(2, 1000*60*60*24*365) // y
@ -218,7 +230,7 @@ func ParseDuration(durationStr string) (Duration, error) {
m(12, 1000) // s
m(14, 1) // ms
return Duration(dur), nil
return Duration(dur), overflowErr
}
func (d Duration) String() string {
@ -254,6 +266,25 @@ func (d Duration) String() string {
return r
}
// MarshalJSON implements the json.Marshaler interface.
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (d *Duration) UnmarshalJSON(bytes []byte) error {
var s string
if err := json.Unmarshal(bytes, &s); err != nil {
return err
}
dur, err := ParseDuration(s)
if err != nil {
return err
}
*d = dur
return nil
}
// MarshalText implements the encoding.TextMarshaler interface.
func (d *Duration) MarshalText() ([]byte, error) {
return []byte(d.String()), nil

2
vendor/modules.txt vendored
View File

@ -177,7 +177,7 @@ github.com/prometheus/client_golang/prometheus/internal
github.com/prometheus/client_golang/prometheus/promhttp
# github.com/prometheus/client_model v0.2.0
github.com/prometheus/client_model/go
# github.com/prometheus/common v0.18.0
# github.com/prometheus/common v0.21.0
## explicit
github.com/prometheus/common/config
github.com/prometheus/common/expfmt