Add ability to use custom prometheus buckets (#7171)

This commit is contained in:
serge-r 2022-01-15 08:27:41 +07:00 committed by GitHub
parent 5f7656f4cc
commit c0098f305c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 7 deletions

View file

@ -22,6 +22,7 @@ import (
"os" "os"
"time" "time"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/pflag" "github.com/spf13/pflag"
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
@ -29,6 +30,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/controller" "k8s.io/ingress-nginx/internal/ingress/controller"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config" ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass" "k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
"k8s.io/ingress-nginx/internal/ingress/metric/collectors"
"k8s.io/ingress-nginx/internal/ingress/status" "k8s.io/ingress-nginx/internal/ingress/status"
ing_net "k8s.io/ingress-nginx/internal/net" ing_net "k8s.io/ingress-nginx/internal/net"
"k8s.io/ingress-nginx/internal/nginx" "k8s.io/ingress-nginx/internal/nginx"
@ -161,6 +163,9 @@ Requires the update-status parameter.`)
`Enables the collection of NGINX metrics`) `Enables the collection of NGINX metrics`)
metricsPerHost = flags.Bool("metrics-per-host", true, metricsPerHost = flags.Bool("metrics-per-host", true,
`Export metrics per-host`) `Export metrics per-host`)
timeBuckets = flags.Float64Slice("time-buckets", prometheus.DefBuckets, "Set of buckets which will be used for prometheus histogram metrics such as RequestTime, ResponseTime")
lengthBuckets = flags.Float64Slice("length-buckets", prometheus.LinearBuckets(10, 10, 10), "Set of buckets which will be used for prometheus histogram metrics such as RequestLength, ResponseLength")
sizeBuckets = flags.Float64Slice("size-buckets", prometheus.ExponentialBuckets(10, 10, 7), "Set of buckets which will be used for prometheus histogram metrics such as BytesSent")
monitorMaxBatchSize = flags.Int("monitor-max-batch-size", 10000, "Max batch size of NGINX metrics") monitorMaxBatchSize = flags.Int("monitor-max-batch-size", 10000, "Max batch size of NGINX metrics")
httpPort = flags.Int("http-port", 80, `Port to use for servicing HTTP traffic.`) httpPort = flags.Int("http-port", 80, `Port to use for servicing HTTP traffic.`)
@ -283,6 +288,12 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
} }
} }
var histogramBuckets = &collectors.HistogramBuckets{
TimeBuckets: *timeBuckets,
LengthBuckets: *lengthBuckets,
SizeBuckets: *sizeBuckets,
}
ngx_config.EnableSSLChainCompletion = *enableSSLChainCompletion ngx_config.EnableSSLChainCompletion = *enableSSLChainCompletion
config := &controller.Configuration{ config := &controller.Configuration{
@ -293,6 +304,7 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
EnableProfiling: *profiling, EnableProfiling: *profiling,
EnableMetrics: *enableMetrics, EnableMetrics: *enableMetrics,
MetricsPerHost: *metricsPerHost, MetricsPerHost: *metricsPerHost,
MetricsBuckets: histogramBuckets,
MonitorMaxBatchSize: *monitorMaxBatchSize, MonitorMaxBatchSize: *monitorMaxBatchSize,
DisableServiceExternalName: *disableServiceExternalName, DisableServiceExternalName: *disableServiceExternalName,
EnableSSLPassthrough: *enableSSLPassthrough, EnableSSLPassthrough: *enableSSLPassthrough,

View file

@ -133,7 +133,7 @@ func main() {
mc := metric.NewDummyCollector() mc := metric.NewDummyCollector()
if conf.EnableMetrics { if conf.EnableMetrics {
mc, err = metric.NewCollector(conf.MetricsPerHost, reg, conf.IngressClassConfiguration.Controller) mc, err = metric.NewCollector(conf.MetricsPerHost, reg, conf.IngressClassConfiguration.Controller, *conf.MetricsBuckets)
if err != nil { if err != nil {
klog.Fatalf("Error creating prometheus collector: %v", err) klog.Fatalf("Error creating prometheus collector: %v", err)
} }

View file

@ -41,6 +41,7 @@ import (
"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass" "k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
"k8s.io/ingress-nginx/internal/ingress/controller/store" "k8s.io/ingress-nginx/internal/ingress/controller/store"
"k8s.io/ingress-nginx/internal/ingress/errors" "k8s.io/ingress-nginx/internal/ingress/errors"
"k8s.io/ingress-nginx/internal/ingress/metric/collectors"
"k8s.io/ingress-nginx/internal/k8s" "k8s.io/ingress-nginx/internal/k8s"
"k8s.io/ingress-nginx/internal/nginx" "k8s.io/ingress-nginx/internal/nginx"
"k8s.io/klog/v2" "k8s.io/klog/v2"
@ -97,6 +98,7 @@ type Configuration struct {
EnableMetrics bool EnableMetrics bool
MetricsPerHost bool MetricsPerHost bool
MetricsBuckets *collectors.HistogramBuckets
FakeCertificate *ingress.SSLCert FakeCertificate *ingress.SSLCert

View file

@ -56,6 +56,13 @@ type socketData struct {
Path string `json:"path"` Path string `json:"path"`
} }
// HistogramBuckets allow customizing prometheus histogram buckets values
type HistogramBuckets struct {
TimeBuckets []float64
LengthBuckets []float64
SizeBuckets []float64
}
// SocketCollector stores prometheus metrics and ingress meta-data // SocketCollector stores prometheus metrics and ingress meta-data
type SocketCollector struct { type SocketCollector struct {
prometheus.Collector prometheus.Collector
@ -79,6 +86,8 @@ type SocketCollector struct {
hosts sets.String hosts sets.String
metricsPerHost bool metricsPerHost bool
buckets HistogramBuckets
} }
var ( var (
@ -101,7 +110,7 @@ var defObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
// NewSocketCollector creates a new SocketCollector instance using // NewSocketCollector creates a new SocketCollector instance using
// the ingress watch namespace and class used by the controller // the ingress watch namespace and class used by the controller
func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*SocketCollector, error) { func NewSocketCollector(pod, namespace, class string, metricsPerHost bool, buckets HistogramBuckets) (*SocketCollector, error) {
socket := "/tmp/prometheus-nginx.socket" socket := "/tmp/prometheus-nginx.socket"
// unix sockets must be unlink()ed before being used // unix sockets must be unlink()ed before being used
_ = syscall.Unlink(socket) _ = syscall.Unlink(socket)
@ -138,6 +147,7 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*Soc
Help: "The time spent on receiving the response from the upstream server", Help: "The time spent on receiving the response from the upstream server",
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
ConstLabels: constLabels, ConstLabels: constLabels,
Buckets: buckets.TimeBuckets,
}, },
requestTags, requestTags,
), ),
@ -147,6 +157,7 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*Soc
Help: "The response length (including request line, header, and request body)", Help: "The response length (including request line, header, and request body)",
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
ConstLabels: constLabels, ConstLabels: constLabels,
Buckets: buckets.LengthBuckets,
}, },
requestTags, requestTags,
), ),
@ -157,6 +168,7 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*Soc
Help: "The request processing time in milliseconds", Help: "The request processing time in milliseconds",
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
ConstLabels: constLabels, ConstLabels: constLabels,
Buckets: buckets.TimeBuckets,
}, },
requestTags, requestTags,
), ),
@ -165,7 +177,7 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*Soc
Name: "request_size", Name: "request_size",
Help: "The request length (including request line, header, and request body)", Help: "The request length (including request line, header, and request body)",
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
Buckets: prometheus.LinearBuckets(10, 10, 10), // 10 buckets, each 10 bytes wide. Buckets: buckets.LengthBuckets,
ConstLabels: constLabels, ConstLabels: constLabels,
}, },
requestTags, requestTags,
@ -186,7 +198,7 @@ func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*Soc
Name: "bytes_sent", Name: "bytes_sent",
Help: "The number of bytes sent to a client", Help: "The number of bytes sent to a client",
Namespace: PrometheusNamespace, Namespace: PrometheusNamespace,
Buckets: prometheus.ExponentialBuckets(10, 10, 7), // 7 buckets, exponential factor of 10. Buckets: buckets.SizeBuckets,
ConstLabels: constLabels, ConstLabels: constLabels,
}, },
requestTags, requestTags,

View file

@ -68,6 +68,17 @@ func TestNewUDPLogListener(t *testing.T) {
} }
func TestCollector(t *testing.T) { func TestCollector(t *testing.T) {
buckets := struct {
TimeBuckets []float64
LengthBuckets []float64
SizeBuckets []float64
}{
prometheus.DefBuckets,
prometheus.LinearBuckets(10, 10, 10),
prometheus.ExponentialBuckets(10, 10, 7),
}
cases := []struct { cases := []struct {
name string name string
data []string data []string
@ -338,7 +349,7 @@ func TestCollector(t *testing.T) {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
registry := prometheus.NewPedanticRegistry() registry := prometheus.NewPedanticRegistry()
sc, err := NewSocketCollector("pod", "default", "ingress", true) sc, err := NewSocketCollector("pod", "default", "ingress", true, buckets)
if err != nil { if err != nil {
t.Errorf("%v: unexpected error creating new SocketCollector: %v", c.name, err) t.Errorf("%v: unexpected error creating new SocketCollector: %v", c.name, err)
} }

View file

@ -68,7 +68,7 @@ type collector struct {
} }
// NewCollector creates a new metric collector the for ingress controller // NewCollector creates a new metric collector the for ingress controller
func NewCollector(metricsPerHost bool, registry *prometheus.Registry, ingressclass string) (Collector, error) { func NewCollector(metricsPerHost bool, registry *prometheus.Registry, ingressclass string, buckets collectors.HistogramBuckets) (Collector, error) {
podNamespace := os.Getenv("POD_NAMESPACE") podNamespace := os.Getenv("POD_NAMESPACE")
if podNamespace == "" { if podNamespace == "" {
podNamespace = "default" podNamespace = "default"
@ -86,7 +86,7 @@ func NewCollector(metricsPerHost bool, registry *prometheus.Registry, ingresscla
return nil, err return nil, err
} }
s, err := collectors.NewSocketCollector(podName, podNamespace, ingressclass, metricsPerHost) s, err := collectors.NewSocketCollector(podName, podNamespace, ingressclass, metricsPerHost, buckets)
if err != nil { if err != nil {
return nil, err return nil, err
} }