diff --git a/pkg/cloudprovider/providers/gce/BUILD b/pkg/cloudprovider/providers/gce/BUILD index f33f482e6e9..23b674b5554 100644 --- a/pkg/cloudprovider/providers/gce/BUILD +++ b/pkg/cloudprovider/providers/gce/BUILD @@ -82,6 +82,7 @@ go_test( "gce_healthchecks_test.go", "gce_loadbalancer_external_test.go", "gce_test.go", + "metrics_test.go", ], library = ":go_default_library", deps = [ diff --git a/pkg/cloudprovider/providers/gce/gce_addresses.go b/pkg/cloudprovider/providers/gce/gce_addresses.go index f3bd9dea780..7e963e901bd 100644 --- a/pkg/cloudprovider/providers/gce/gce_addresses.go +++ b/pkg/cloudprovider/providers/gce/gce_addresses.go @@ -18,7 +18,6 @@ package gce import ( "fmt" - "time" "github.com/golang/glog" computealpha "google.golang.org/api/compute/v0.alpha" @@ -26,10 +25,11 @@ import ( ) func newAddressMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"address_" + request, region, unusedMetricLabel}, - } + return newAddressMetricContextWithVersion(request, region, computeV1Version) +} + +func newAddressMetricContextWithVersion(request, region, version string) *metricContext { + return newGenericMetricContext("address", request, region, unusedMetricLabel, version) } // ReserveGlobalAddress creates a global address. @@ -74,7 +74,7 @@ func (gce *GCECloud) ReserveRegionAddress(addr *compute.Address, region string) // ReserveAlphaRegionAddress creates an Alpha, regional address. func (gce *GCECloud) ReserveAlphaRegionAddress(addr *computealpha.Address, region string) error { - mc := newAddressMetricContext("reserve", region) + mc := newAddressMetricContextWithVersion("reserve", region, computeAlphaVersion) op, err := gce.serviceAlpha.Addresses.Insert(gce.projectID, region, addr).Do() if err != nil { return mc.Observe(err) @@ -101,7 +101,7 @@ func (gce *GCECloud) GetRegionAddress(name, region string) (*compute.Address, er // GetAlphaRegionAddress returns the Alpha, regional address by name. func (gce *GCECloud) GetAlphaRegionAddress(name, region string) (*computealpha.Address, error) { - mc := newAddressMetricContext("get", region) + mc := newAddressMetricContextWithVersion("get", region, computeAlphaVersion) v, err := gce.serviceAlpha.Addresses.Get(gce.projectID, region, name).Do() return v, mc.Observe(err) } diff --git a/pkg/cloudprovider/providers/gce/gce_backendservice.go b/pkg/cloudprovider/providers/gce/gce_backendservice.go index d460c6157d8..7bf3d73e0d8 100644 --- a/pkg/cloudprovider/providers/gce/gce_backendservice.go +++ b/pkg/cloudprovider/providers/gce/gce_backendservice.go @@ -18,16 +18,12 @@ package gce import ( "net/http" - "time" compute "google.golang.org/api/compute/v1" ) func newBackendServiceMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"backendservice_" + request, region, unusedMetricLabel}, - } + return newGenericMetricContext("backendservice", request, region, unusedMetricLabel, computeV1Version) } // GetGlobalBackendService retrieves a backend by name. diff --git a/pkg/cloudprovider/providers/gce/gce_cert.go b/pkg/cloudprovider/providers/gce/gce_cert.go index 77af58bbe3c..e981fe71765 100644 --- a/pkg/cloudprovider/providers/gce/gce_cert.go +++ b/pkg/cloudprovider/providers/gce/gce_cert.go @@ -18,16 +18,12 @@ package gce import ( "net/http" - "time" compute "google.golang.org/api/compute/v1" ) func newCertMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"cert_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("cert", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } // GetSslCertificate returns the SslCertificate by name. diff --git a/pkg/cloudprovider/providers/gce/gce_clusters.go b/pkg/cloudprovider/providers/gce/gce_clusters.go index 4524d483f69..dad330ca5d5 100644 --- a/pkg/cloudprovider/providers/gce/gce_clusters.go +++ b/pkg/cloudprovider/providers/gce/gce_clusters.go @@ -16,13 +16,8 @@ limitations under the License. package gce -import "time" - func newClustersMetricContext(request, zone string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"clusters_" + request, unusedMetricLabel, zone}, - } + return newGenericMetricContext("clusters", request, unusedMetricLabel, zone, computeV1Version) } func (gce *GCECloud) ListClusters() ([]string, error) { diff --git a/pkg/cloudprovider/providers/gce/gce_disks.go b/pkg/cloudprovider/providers/gce/gce_disks.go index c916989b5ee..57ca223da73 100644 --- a/pkg/cloudprovider/providers/gce/gce_disks.go +++ b/pkg/cloudprovider/providers/gce/gce_disks.go @@ -21,7 +21,6 @@ import ( "fmt" "net/http" "strings" - "time" "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/cloudprovider" @@ -85,10 +84,7 @@ type GCEDisk struct { } func newDiskMetricContext(request, zone string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"disk_" + request, unusedMetricLabel, zone}, - } + return newGenericMetricContext("disk", request, unusedMetricLabel, zone, computeV1Version) } func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error { diff --git a/pkg/cloudprovider/providers/gce/gce_firewall.go b/pkg/cloudprovider/providers/gce/gce_firewall.go index 668f2e05522..b08d3f28067 100644 --- a/pkg/cloudprovider/providers/gce/gce_firewall.go +++ b/pkg/cloudprovider/providers/gce/gce_firewall.go @@ -17,16 +17,11 @@ limitations under the License. package gce import ( - "time" - compute "google.golang.org/api/compute/v1" ) func newFirewallMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"firewall_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("firewall", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } // GetFirewall returns the Firewall by name. diff --git a/pkg/cloudprovider/providers/gce/gce_forwardingrule.go b/pkg/cloudprovider/providers/gce/gce_forwardingrule.go index 8a7110da6ba..0473c44266d 100644 --- a/pkg/cloudprovider/providers/gce/gce_forwardingrule.go +++ b/pkg/cloudprovider/providers/gce/gce_forwardingrule.go @@ -17,17 +17,15 @@ limitations under the License. package gce import ( - "time" - computealpha "google.golang.org/api/compute/v0.alpha" compute "google.golang.org/api/compute/v1" ) func newForwardingRuleMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"forwardingrule_" + request, region, unusedMetricLabel}, - } + return newForwardingRuleMetricContextWithVersion(request, region, computeV1Version) +} +func newForwardingRuleMetricContextWithVersion(request, region, version string) *metricContext { + return newGenericMetricContext("forwardingrule", request, region, unusedMetricLabel, version) } // CreateGlobalForwardingRule creates the passed GlobalForwardingRule @@ -88,7 +86,7 @@ func (gce *GCECloud) GetRegionForwardingRule(name, region string) (*compute.Forw // GetAlphaRegionForwardingRule returns the Alpha forwarding rule by name & region. func (gce *GCECloud) GetAlphaRegionForwardingRule(name, region string) (*computealpha.ForwardingRule, error) { - mc := newForwardingRuleMetricContext("get", region) + mc := newForwardingRuleMetricContextWithVersion("get", region, computeAlphaVersion) v, err := gce.serviceAlpha.ForwardingRules.Get(gce.projectID, region, name).Do() return v, mc.Observe(err) } @@ -116,7 +114,7 @@ func (gce *GCECloud) CreateRegionForwardingRule(rule *compute.ForwardingRule, re // CreateAlphaRegionForwardingRule creates and returns an Alpha // forwarding fule in the given region. func (gce *GCECloud) CreateAlphaRegionForwardingRule(rule *computealpha.ForwardingRule, region string) error { - mc := newForwardingRuleMetricContext("create", region) + mc := newForwardingRuleMetricContextWithVersion("create", region, computeAlphaVersion) op, err := gce.serviceAlpha.ForwardingRules.Insert(gce.projectID, region, rule).Do() if err != nil { return mc.Observe(err) diff --git a/pkg/cloudprovider/providers/gce/gce_healthchecks.go b/pkg/cloudprovider/providers/gce/gce_healthchecks.go index 9fd2989b2a6..85f077f0007 100644 --- a/pkg/cloudprovider/providers/gce/gce_healthchecks.go +++ b/pkg/cloudprovider/providers/gce/gce_healthchecks.go @@ -17,8 +17,6 @@ limitations under the License. package gce import ( - "time" - "k8s.io/api/core/v1" "k8s.io/kubernetes/pkg/master/ports" utilversion "k8s.io/kubernetes/pkg/util/version" @@ -45,10 +43,7 @@ func init() { } func newHealthcheckMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"healthcheck_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("healthcheck", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } // GetHttpHealthCheck returns the given HttpHealthCheck by name. diff --git a/pkg/cloudprovider/providers/gce/gce_instancegroup.go b/pkg/cloudprovider/providers/gce/gce_instancegroup.go index 044847ab3b4..67083224bb2 100644 --- a/pkg/cloudprovider/providers/gce/gce_instancegroup.go +++ b/pkg/cloudprovider/providers/gce/gce_instancegroup.go @@ -16,17 +16,10 @@ limitations under the License. package gce -import ( - "time" - - compute "google.golang.org/api/compute/v1" -) +import compute "google.golang.org/api/compute/v1" func newInstanceGroupMetricContext(request string, zone string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"instancegroup_" + request, unusedMetricLabel, zone}, - } + return newGenericMetricContext("instancegroup", request, unusedMetricLabel, zone, computeV1Version) } // CreateInstanceGroup creates an instance group with the given diff --git a/pkg/cloudprovider/providers/gce/gce_instances.go b/pkg/cloudprovider/providers/gce/gce_instances.go index 8d997ae9ed4..4c1c4af6c96 100644 --- a/pkg/cloudprovider/providers/gce/gce_instances.go +++ b/pkg/cloudprovider/providers/gce/gce_instances.go @@ -41,10 +41,7 @@ const ( ) func newInstancesMetricContext(request, zone string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"instances_" + request, unusedMetricLabel, zone}, - } + return newGenericMetricContext("instances", request, unusedMetricLabel, zone, computeV1Version) } func splitNodesByZone(nodes []*v1.Node) map[string][]*v1.Node { diff --git a/pkg/cloudprovider/providers/gce/gce_loadbalancer.go b/pkg/cloudprovider/providers/gce/gce_loadbalancer.go index 7026df8fea1..ba2fa03cdb8 100644 --- a/pkg/cloudprovider/providers/gce/gce_loadbalancer.go +++ b/pkg/cloudprovider/providers/gce/gce_loadbalancer.go @@ -21,7 +21,6 @@ import ( "fmt" "net" "strings" - "time" "github.com/golang/glog" @@ -40,10 +39,7 @@ var ( ) func newLoadBalancerMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"loadbalancer_" + request, region, unusedMetricLabel}, - } + return newGenericMetricContext("loadbalancer", request, region, unusedMetricLabel, computeV1Version) } type lbScheme string diff --git a/pkg/cloudprovider/providers/gce/gce_routes.go b/pkg/cloudprovider/providers/gce/gce_routes.go index 1e0d82661b5..5f6459cd1a8 100644 --- a/pkg/cloudprovider/providers/gce/gce_routes.go +++ b/pkg/cloudprovider/providers/gce/gce_routes.go @@ -20,7 +20,6 @@ import ( "fmt" "net/http" "path" - "time" "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/cloudprovider" @@ -30,10 +29,7 @@ import ( ) func newRoutesMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"routes_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("routes", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) { diff --git a/pkg/cloudprovider/providers/gce/gce_targetpool.go b/pkg/cloudprovider/providers/gce/gce_targetpool.go index 9de1f6befb9..0efe15adfc0 100644 --- a/pkg/cloudprovider/providers/gce/gce_targetpool.go +++ b/pkg/cloudprovider/providers/gce/gce_targetpool.go @@ -16,17 +16,10 @@ limitations under the License. package gce -import ( - "time" - - compute "google.golang.org/api/compute/v1" -) +import compute "google.golang.org/api/compute/v1" func newTargetPoolMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"targetpool_" + request, region, unusedMetricLabel}, - } + return newGenericMetricContext("targetpool", request, region, unusedMetricLabel, computeV1Version) } // GetTargetPool returns the TargetPool by name. diff --git a/pkg/cloudprovider/providers/gce/gce_targetproxy.go b/pkg/cloudprovider/providers/gce/gce_targetproxy.go index af5a52855d4..b92206cfc4e 100644 --- a/pkg/cloudprovider/providers/gce/gce_targetproxy.go +++ b/pkg/cloudprovider/providers/gce/gce_targetproxy.go @@ -18,16 +18,12 @@ package gce import ( "net/http" - "time" compute "google.golang.org/api/compute/v1" ) func newTargetProxyMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"targetproxy_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("targetproxy", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } // GetTargetHttpProxy returns the UrlMap by name. diff --git a/pkg/cloudprovider/providers/gce/gce_urlmap.go b/pkg/cloudprovider/providers/gce/gce_urlmap.go index f19db2f23a7..60184ac4354 100644 --- a/pkg/cloudprovider/providers/gce/gce_urlmap.go +++ b/pkg/cloudprovider/providers/gce/gce_urlmap.go @@ -18,16 +18,12 @@ package gce import ( "net/http" - "time" compute "google.golang.org/api/compute/v1" ) func newUrlMapMetricContext(request string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"urlmap_" + request, unusedMetricLabel, unusedMetricLabel}, - } + return newGenericMetricContext("urlmap", request, unusedMetricLabel, unusedMetricLabel, computeV1Version) } // GetUrlMap returns the UrlMap by name. diff --git a/pkg/cloudprovider/providers/gce/gce_zones.go b/pkg/cloudprovider/providers/gce/gce_zones.go index 3179e757892..212e740893c 100644 --- a/pkg/cloudprovider/providers/gce/gce_zones.go +++ b/pkg/cloudprovider/providers/gce/gce_zones.go @@ -18,7 +18,6 @@ package gce import ( "fmt" - "time" compute "google.golang.org/api/compute/v1" @@ -27,10 +26,7 @@ import ( ) func newZonesMetricContext(request, region string) *metricContext { - return &metricContext{ - start: time.Now(), - attributes: []string{"zones_" + request, region, unusedMetricLabel}, - } + return newGenericMetricContext("zones", request, region, unusedMetricLabel, computeV1Version) } // GetZone creates a cloudprovider.Zone of the current zone and region diff --git a/pkg/cloudprovider/providers/gce/metrics.go b/pkg/cloudprovider/providers/gce/metrics.go index 16536898f9b..649bd11b132 100644 --- a/pkg/cloudprovider/providers/gce/metrics.go +++ b/pkg/cloudprovider/providers/gce/metrics.go @@ -22,21 +22,33 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +const ( + // Version strings for recording metrics. + computeV1Version = "v1" + computeAlphaVersion = "alpha" + computeBetaVersion = "beta" +) + type apiCallMetrics struct { latency *prometheus.HistogramVec errors *prometheus.CounterVec } var ( - apiMetrics = registerAPIMetrics( + metricLabels = []string{ "request", // API function that is begin invoked. "region", // region (optional). "zone", // zone (optional). - ) + "version", // API version. + } + + apiMetrics = registerAPIMetrics(metricLabels...) ) type metricContext struct { - start time.Time + start time.Time + // The cardinalities of attributes and metricLabels (defined above) must + // match, or prometheus will panic. attributes []string } @@ -54,6 +66,13 @@ func (mc *metricContext) Observe(err error) error { return err } +func newGenericMetricContext(prefix, request, region, zone, version string) *metricContext { + return &metricContext{ + start: time.Now(), + attributes: []string{prefix + "_" + request, region, zone, version}, + } +} + // registerApiMetrics adds metrics definitions for a category of API calls. func registerAPIMetrics(attributes ...string) *apiCallMetrics { metrics := &apiCallMetrics{ diff --git a/pkg/cloudprovider/providers/gce/metrics_test.go b/pkg/cloudprovider/providers/gce/metrics_test.go new file mode 100644 index 00000000000..89fde2ac4b6 --- /dev/null +++ b/pkg/cloudprovider/providers/gce/metrics_test.go @@ -0,0 +1,28 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gce + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVerifyMetricLabelCardinality(t *testing.T) { + mc := newGenericMetricContext("foo", "get", "us-central1", "", "alpha") + assert.Len(t, mc.attributes, len(metricLabels), "cardinalities of labels and values must match") +}