From f33a2090dd9bbab19394510e8859235f72a6d9b0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 21 Dec 2018 17:10:28 +0000 Subject: [PATCH] Add a flag to make per-host metrics optional When serving many hosts from one nginx, the metrics may become too numerous for Prometheus. Add a flag to disable the host label, so that metrics are totalled across all hosts. --- cmd/nginx/flags.go | 3 +++ cmd/nginx/main.go | 2 +- internal/ingress/controller/controller.go | 3 ++- internal/ingress/metric/collectors/socket.go | 18 ++++++++++++++---- .../ingress/metric/collectors/socket_test.go | 2 +- internal/ingress/metric/main.go | 4 ++-- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go index b2e491cf55..d32028a3b6 100644 --- a/cmd/nginx/flags.go +++ b/cmd/nginx/flags.go @@ -149,6 +149,8 @@ Feature backed by OpenResty Lua libraries. Requires that OCSP stapling is not en enableMetrics = flags.Bool("enable-metrics", true, `Enables the collection of NGINX metrics`) + metricsPerHost = flags.Bool("metrics-per-host", true, + `Export metrics per-host`) httpPort = flags.Int("http-port", 80, `Port to use for servicing HTTP traffic.`) httpsPort = flags.Int("https-port", 443, `Port to use for servicing HTTPS traffic.`) @@ -227,6 +229,7 @@ Feature backed by OpenResty Lua libraries. Requires that OCSP stapling is not en ElectionID: *electionID, EnableProfiling: *profiling, EnableMetrics: *enableMetrics, + MetricsPerHost: *metricsPerHost, EnableSSLPassthrough: *enableSSLPassthrough, EnableSSLChainCompletion: *enableSSLChainCompletion, ResyncPeriod: *resyncPeriod, diff --git a/cmd/nginx/main.go b/cmd/nginx/main.go index 295b2f42e1..5f5b4b9cb2 100644 --- a/cmd/nginx/main.go +++ b/cmd/nginx/main.go @@ -131,7 +131,7 @@ func main() { mc := metric.NewDummyCollector() if conf.EnableMetrics { - mc, err = metric.NewCollector(conf.ListenPorts.Status, reg) + mc, err = metric.NewCollector(conf.ListenPorts.Status, conf.MetricsPerHost, reg) if err != nil { klog.Fatalf("Error creating prometheus collector: %v", err) } diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index cd970ee140..d74b03b5aa 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -87,7 +87,8 @@ type Configuration struct { EnableProfiling bool - EnableMetrics bool + EnableMetrics bool + MetricsPerHost bool EnableSSLChainCompletion bool diff --git a/internal/ingress/metric/collectors/socket.go b/internal/ingress/metric/collectors/socket.go index 7421602f1d..406a8b7679 100644 --- a/internal/ingress/metric/collectors/socket.go +++ b/internal/ingress/metric/collectors/socket.go @@ -76,12 +76,12 @@ type SocketCollector struct { metricMapping map[string]interface{} hosts sets.String + + metricsPerHost bool } var ( requestTags = []string{ - "host", - "status", "method", @@ -95,7 +95,7 @@ var ( // NewSocketCollector creates a new SocketCollector instance using // the ingress watch namespace and class used by the controller -func NewSocketCollector(pod, namespace, class string) (*SocketCollector, error) { +func NewSocketCollector(pod, namespace, class string, metricsPerHost bool) (*SocketCollector, error) { socket := "/tmp/prometheus-nginx.socket" listener, err := net.Listen("unix", socket) if err != nil { @@ -113,9 +113,16 @@ func NewSocketCollector(pod, namespace, class string) (*SocketCollector, error) "controller_pod": pod, } + requestTags := requestTags + if metricsPerHost { + requestTags = append(requestTags, "host") + } + sc := &SocketCollector{ listener: listener, + metricsPerHost: metricsPerHost, + responseTime: prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "response_duration_seconds", @@ -219,8 +226,8 @@ func (sc *SocketCollector) handleMessage(msg []byte) { continue } + // Note these must match the order in requestTags at the top requestLabels := prometheus.Labels{ - "host": stats.Host, "status": stats.Status, "method": stats.Method, "path": stats.Path, @@ -228,6 +235,9 @@ func (sc *SocketCollector) handleMessage(msg []byte) { "ingress": stats.Ingress, "service": stats.Service, } + if sc.metricsPerHost { + requestLabels["host"] = stats.Host + } collectorLabels := prometheus.Labels{ "namespace": stats.Namespace, diff --git a/internal/ingress/metric/collectors/socket_test.go b/internal/ingress/metric/collectors/socket_test.go index f347f09dc6..b9b3c68482 100644 --- a/internal/ingress/metric/collectors/socket_test.go +++ b/internal/ingress/metric/collectors/socket_test.go @@ -288,7 +288,7 @@ func TestCollector(t *testing.T) { t.Run(c.name, func(t *testing.T) { registry := prometheus.NewPedanticRegistry() - sc, err := NewSocketCollector("pod", "default", "ingress") + sc, err := NewSocketCollector("pod", "default", "ingress", true) if err != nil { t.Errorf("%v: unexpected error creating new SocketCollector: %v", c.name, err) } diff --git a/internal/ingress/metric/main.go b/internal/ingress/metric/main.go index df763b679c..c25343aeaa 100644 --- a/internal/ingress/metric/main.go +++ b/internal/ingress/metric/main.go @@ -59,7 +59,7 @@ type collector struct { } // NewCollector creates a new metric collector the for ingress controller -func NewCollector(statusPort int, registry *prometheus.Registry) (Collector, error) { +func NewCollector(statusPort int, metricsPerHost bool, registry *prometheus.Registry) (Collector, error) { podNamespace := os.Getenv("POD_NAMESPACE") if podNamespace == "" { podNamespace = "default" @@ -77,7 +77,7 @@ func NewCollector(statusPort int, registry *prometheus.Registry) (Collector, err return nil, err } - s, err := collectors.NewSocketCollector(podName, podNamespace, class.IngressClass) + s, err := collectors.NewSocketCollector(podName, podNamespace, class.IngressClass, metricsPerHost) if err != nil { return nil, err }