diff --git a/agent/consul/state/state_store_test.go b/agent/consul/state/state_store_test.go index 9434b203e4..a6ddd181dc 100644 --- a/agent/consul/state/state_store_test.go +++ b/agent/consul/state/state_store_test.go @@ -7,10 +7,12 @@ import ( "time" "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-uuid" "github.com/stretchr/testify/require" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/types" ) @@ -57,6 +59,16 @@ func testStateStore(t *testing.T) *Store { return s } +// testRegisterPeering registers a peering into the state store. +func testRegisterPeering(t *testing.T, s *Store, idx uint64, name string) *pbpeering.Peering { + uuid, err := uuid.GenerateUUID() + require.NoError(t, err) + peering := &pbpeering.Peering{Name: name, ID: uuid} + err = s.PeeringWrite(idx, peering) + require.NoError(t, err) + return peering +} + // testRegisterNode registers a node into the state store. func testRegisterNode(t *testing.T, s *Store, idx uint64, nodeID string) { testRegisterNodeOpts(t, s, idx, nodeID) diff --git a/agent/consul/state/usage.go b/agent/consul/state/usage.go index 00784af096..86b0d80ee8 100644 --- a/agent/consul/state/usage.go +++ b/agent/consul/state/usage.go @@ -3,7 +3,7 @@ package state import ( "fmt" - memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-memdb" "github.com/hashicorp/consul/agent/structs" ) @@ -66,6 +66,13 @@ type NodeUsage struct { EnterpriseNodeUsage } +// PeeringUsage contains all of the usage data related to peerings. +type PeeringUsage struct { + // Number of peerings. + Peerings int + EnterprisePeeringUsage +} + type KVUsage struct { KVCount int EnterpriseKVUsage @@ -107,6 +114,10 @@ func updateUsage(tx WriteTxn, changes Changes) error { usageDeltas[change.Table] += delta addEnterpriseNodeUsage(usageDeltas, change) + case tablePeering: + usageDeltas[change.Table] += delta + addEnterprisePeeringUsage(usageDeltas, change) + case tableServices: svc := changeObject(change).(*structs.ServiceNode) if svc.PeerName != "" { @@ -330,6 +341,28 @@ func (s *Store) NodeUsage() (uint64, NodeUsage, error) { return nodes.Index, results, nil } +// PeeringUsage returns the latest seen Raft index, a compiled set of peering usage +// data, and any errors. +func (s *Store) PeeringUsage() (uint64, PeeringUsage, error) { + tx := s.db.ReadTxn() + defer tx.Abort() + + peerings, err := firstUsageEntry(tx, tablePeering) + if err != nil { + return 0, PeeringUsage{}, fmt.Errorf("failed peerings lookup: %s", err) + } + + usage := PeeringUsage{ + Peerings: peerings.Count, + } + results, err := compileEnterprisePeeringUsage(tx, usage) + if err != nil { + return 0, PeeringUsage{}, fmt.Errorf("failed peerings lookup: %s", err) + } + + return peerings.Index, results, nil +} + // ServiceUsage returns the latest seen Raft index, a compiled set of service // usage data, and any errors. func (s *Store) ServiceUsage() (uint64, ServiceUsage, error) { diff --git a/agent/consul/state/usage_oss.go b/agent/consul/state/usage_oss.go index c8975be3b1..edea0e81fc 100644 --- a/agent/consul/state/usage_oss.go +++ b/agent/consul/state/usage_oss.go @@ -4,18 +4,21 @@ package state import ( - memdb "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-memdb" "github.com/hashicorp/consul/agent/structs" ) type EnterpriseServiceUsage struct{} type EnterpriseNodeUsage struct{} +type EnterprisePeeringUsage struct{} type EnterpriseKVUsage struct{} type EnterpriseConfigEntryUsage struct{} func addEnterpriseNodeUsage(map[string]int, memdb.Change) {} +func addEnterprisePeeringUsage(map[string]int, memdb.Change) {} + func addEnterpriseServiceInstanceUsage(map[string]int, memdb.Change) {} func addEnterpriseServiceUsage(map[string]int, map[structs.ServiceName]uniqueServiceState) {} @@ -34,6 +37,10 @@ func compileEnterpriseNodeUsage(tx ReadTxn, usage NodeUsage) (NodeUsage, error) return usage, nil } +func compileEnterprisePeeringUsage(tx ReadTxn, usage PeeringUsage) (PeeringUsage, error) { + return usage, nil +} + func compileEnterpriseKVUsage(tx ReadTxn, usage KVUsage) (KVUsage, error) { return usage, nil } diff --git a/agent/consul/state/usage_test.go b/agent/consul/state/usage_test.go index 43ce6cf9cf..223e1b062f 100644 --- a/agent/consul/state/usage_test.go +++ b/agent/consul/state/usage_test.go @@ -72,6 +72,42 @@ func TestStateStore_Usage_NodeUsagePeering(t *testing.T) { }) } +func TestStateStore_Usage_PeeringUsage(t *testing.T) { + s := testStateStore(t) + + // No nodes have been registered, and thus no usage entry exists + idx, usage, err := s.PeeringUsage() + require.NoError(t, err) + require.Equal(t, idx, uint64(0)) + require.Equal(t, usage.Peerings, 0) + + testRegisterPeering(t, s, 0, "test-peering1") + testRegisterPeering(t, s, 1, "test-peering2") + + idx, usage, err = s.PeeringUsage() + require.NoError(t, err) + require.Equal(t, idx, uint64(1)) + require.Equal(t, usage.Peerings, 2) +} + +func TestStateStore_Usage_PeeringUsage_Delete(t *testing.T) { + s := testStateStore(t) + + testRegisterPeering(t, s, 0, "test-peering1") + peering2 := testRegisterPeering(t, s, 1, "test-peering2") + + idx, usage, err := s.PeeringUsage() + require.NoError(t, err) + require.Equal(t, idx, uint64(1)) + require.Equal(t, usage.Peerings, 2) + + require.NoError(t, s.PeeringTerminateByID(2, peering2.ID)) + idx, usage, err = s.PeeringUsage() + require.NoError(t, err) + require.Equal(t, uint64(2), idx) + require.Equal(t, 2, usage.Peerings) +} + func TestStateStore_Usage_KVUsage(t *testing.T) { s := testStateStore(t) diff --git a/agent/consul/usagemetrics/usagemetrics.go b/agent/consul/usagemetrics/usagemetrics.go index 6733ed3df0..0983cecd84 100644 --- a/agent/consul/usagemetrics/usagemetrics.go +++ b/agent/consul/usagemetrics/usagemetrics.go @@ -20,6 +20,10 @@ var Gauges = []prometheus.GaugeDefinition{ Name: []string{"consul", "state", "nodes"}, Help: "Measures the current number of nodes registered with Consul. It is only emitted by Consul servers. Added in v1.9.0.", }, + { + Name: []string{"consul", "state", "peerings"}, + Help: "Measures the current number of peerings registered with Consul. It is only emitted by Consul servers. Added in v1.13.0.", + }, { Name: []string{"consul", "state", "services"}, Help: "Measures the current number of unique services registered with Consul, based on service name. It is only emitted by Consul servers. Added in v1.9.0.", @@ -167,6 +171,13 @@ func (u *UsageMetricsReporter) runOnce() { u.emitNodeUsage(nodeUsage) + _, peeringUsage, err := state.PeeringUsage() + if err != nil { + u.logger.Warn("failed to retrieve peerings from state store", "error", err) + } + + u.emitPeeringUsage(peeringUsage) + _, serviceUsage, err := state.ServiceUsage() if err != nil { u.logger.Warn("failed to retrieve services from state store", "error", err) diff --git a/agent/consul/usagemetrics/usagemetrics_oss.go b/agent/consul/usagemetrics/usagemetrics_oss.go index 661fd6d34f..2aa35870cf 100644 --- a/agent/consul/usagemetrics/usagemetrics_oss.go +++ b/agent/consul/usagemetrics/usagemetrics_oss.go @@ -19,6 +19,14 @@ func (u *UsageMetricsReporter) emitNodeUsage(nodeUsage state.NodeUsage) { ) } +func (u *UsageMetricsReporter) emitPeeringUsage(peeringUsage state.PeeringUsage) { + metrics.SetGaugeWithLabels( + []string{"consul", "state", "peerings"}, + float32(peeringUsage.Peerings), + u.metricLabels, + ) +} + func (u *UsageMetricsReporter) emitMemberUsage(members []serf.Member) { var ( servers int diff --git a/agent/consul/usagemetrics/usagemetrics_oss_test.go b/agent/consul/usagemetrics/usagemetrics_oss_test.go index 9a25cb0ff2..cfa86b791f 100644 --- a/agent/consul/usagemetrics/usagemetrics_oss_test.go +++ b/agent/consul/usagemetrics/usagemetrics_oss_test.go @@ -8,13 +8,14 @@ import ( "time" "github.com/armon/go-metrics" - "github.com/stretchr/testify/require" - + "github.com/hashicorp/go-uuid" "github.com/hashicorp/serf/serf" + "github.com/stretchr/testify/require" "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/sdk/testutil" ) @@ -37,6 +38,12 @@ func TestUsageReporter_emitNodeUsage_OSS(t *testing.T) { Value: 0, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.clients;datacenter=dc1": { Name: "consul.usage.test.consul.members.clients", @@ -222,6 +229,12 @@ func TestUsageReporter_emitNodeUsage_OSS(t *testing.T) { Value: 3, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.servers;datacenter=dc1": { Name: "consul.usage.test.consul.members.servers", @@ -412,6 +425,409 @@ func TestUsageReporter_emitNodeUsage_OSS(t *testing.T) { } } +func TestUsageReporter_emitPeeringUsage_OSS(t *testing.T) { + type testCase struct { + modfiyStateStore func(t *testing.T, s *state.Store) + getMembersFunc getMembersFunc + expectedGauges map[string]metrics.GaugeValue + } + cases := map[string]testCase{ + "empty-state": { + expectedGauges: map[string]metrics.GaugeValue{ + // --- node --- + "consul.usage.test.consul.state.nodes;datacenter=dc1": { + Name: "consul.usage.test.consul.state.nodes", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- member --- + "consul.usage.test.consul.members.clients;datacenter=dc1": { + Name: "consul.usage.test.consul.members.clients", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + "consul.usage.test.consul.members.servers;datacenter=dc1": { + Name: "consul.usage.test.consul.members.servers", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- service --- + "consul.usage.test.consul.state.services;datacenter=dc1": { + Name: "consul.usage.test.consul.state.services", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + "consul.usage.test.consul.state.service_instances;datacenter=dc1": { + Name: "consul.usage.test.consul.state.service_instances", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- service mesh --- + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=connect-proxy": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "connect-proxy"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=terminating-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "terminating-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=ingress-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "ingress-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=mesh-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "mesh-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=connect-native": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "connect-native"}, + }, + }, + // --- kv --- + "consul.usage.test.consul.state.kv_entries;datacenter=dc1": { + Name: "consul.usage.test.consul.state.kv_entries", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- config entries --- + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-intentions": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-intentions"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-resolver": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-resolver"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-router": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-router"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-defaults": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-defaults"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=ingress-gateway": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "ingress-gateway"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-splitter": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-splitter"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=mesh": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "mesh"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=proxy-defaults": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "proxy-defaults"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=terminating-gateway": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "terminating-gateway"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=exported-services": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "exported-services"}, + }, + }, + }, + getMembersFunc: func() []serf.Member { return []serf.Member{} }, + }, + "peerings": { + modfiyStateStore: func(t *testing.T, s *state.Store) { + id, err := uuid.GenerateUUID() + require.NoError(t, err) + require.NoError(t, s.PeeringWrite(1, &pbpeering.Peering{Name: "foo", ID: id})) + id, err = uuid.GenerateUUID() + require.NoError(t, err) + require.NoError(t, s.PeeringWrite(2, &pbpeering.Peering{Name: "bar", ID: id})) + id, err = uuid.GenerateUUID() + require.NoError(t, err) + require.NoError(t, s.PeeringWrite(3, &pbpeering.Peering{Name: "baz", ID: id})) + }, + getMembersFunc: func() []serf.Member { + return []serf.Member{ + { + Name: "foo", + Tags: map[string]string{"role": "consul"}, + Status: serf.StatusAlive, + }, + { + Name: "bar", + Tags: map[string]string{"role": "consul"}, + Status: serf.StatusAlive, + }, + } + }, + expectedGauges: map[string]metrics.GaugeValue{ + // --- node --- + "consul.usage.test.consul.state.nodes;datacenter=dc1": { + Name: "consul.usage.test.consul.state.nodes", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 3, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- member --- + "consul.usage.test.consul.members.servers;datacenter=dc1": { + Name: "consul.usage.test.consul.members.servers", + Value: 2, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + "consul.usage.test.consul.members.clients;datacenter=dc1": { + Name: "consul.usage.test.consul.members.clients", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- service --- + "consul.usage.test.consul.state.services;datacenter=dc1": { + Name: "consul.usage.test.consul.state.services", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + "consul.usage.test.consul.state.service_instances;datacenter=dc1": { + Name: "consul.usage.test.consul.state.service_instances", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- service mesh --- + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=connect-proxy": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "connect-proxy"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=terminating-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "terminating-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=ingress-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "ingress-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=mesh-gateway": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "mesh-gateway"}, + }, + }, + "consul.usage.test.consul.state.connect_instances;datacenter=dc1;kind=connect-native": { + Name: "consul.usage.test.consul.state.connect_instances", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "connect-native"}, + }, + }, + // --- kv --- + "consul.usage.test.consul.state.kv_entries;datacenter=dc1": { + Name: "consul.usage.test.consul.state.kv_entries", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, + // --- config entries --- + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-intentions": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-intentions"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-resolver": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-resolver"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-router": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-router"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-defaults": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-defaults"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=ingress-gateway": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "ingress-gateway"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=service-splitter": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "service-splitter"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=mesh": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "mesh"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=proxy-defaults": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "proxy-defaults"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=terminating-gateway": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "terminating-gateway"}, + }, + }, + "consul.usage.test.consul.state.config_entries;datacenter=dc1;kind=exported-services": { + Name: "consul.usage.test.consul.state.config_entries", + Value: 0, + Labels: []metrics.Label{ + {Name: "datacenter", Value: "dc1"}, + {Name: "kind", Value: "exported-services"}, + }, + }, + }, + }, + } + + for name, tcase := range cases { + t.Run(name, func(t *testing.T) { + // Only have a single interval for the test + sink := metrics.NewInmemSink(1*time.Minute, 1*time.Minute) + cfg := metrics.DefaultConfig("consul.usage.test") + cfg.EnableHostname = false + metrics.NewGlobal(cfg, sink) + + mockStateProvider := &mockStateProvider{} + s, err := newStateStore() + require.NoError(t, err) + if tcase.modfiyStateStore != nil { + tcase.modfiyStateStore(t, s) + } + mockStateProvider.On("State").Return(s) + + reporter, err := NewUsageMetricsReporter( + new(Config). + WithStateProvider(mockStateProvider). + WithLogger(testutil.Logger(t)). + WithDatacenter("dc1"). + WithGetMembersFunc(tcase.getMembersFunc), + ) + require.NoError(t, err) + + reporter.runOnce() + + intervals := sink.Data() + require.Len(t, intervals, 1) + intv := intervals[0] + + assertEqualGaugeMaps(t, tcase.expectedGauges, intv.Gauges) + }) + } +} + func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { type testCase struct { modfiyStateStore func(t *testing.T, s *state.Store) @@ -427,6 +843,12 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { Value: 0, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.servers;datacenter=dc1": { Name: "consul.usage.test.consul.members.servers", @@ -654,6 +1076,12 @@ func TestUsageReporter_emitServiceUsage_OSS(t *testing.T) { Value: 4, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.servers;datacenter=dc1": { Name: "consul.usage.test.consul.members.servers", @@ -866,6 +1294,12 @@ func TestUsageReporter_emitKVUsage_OSS(t *testing.T) { Value: 0, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.clients;datacenter=dc1": { Name: "consul.usage.test.consul.members.clients", @@ -1060,6 +1494,12 @@ func TestUsageReporter_emitKVUsage_OSS(t *testing.T) { Value: 3, Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, }, + // --- peering --- + "consul.usage.test.consul.state.peerings;datacenter=dc1": { + Name: "consul.usage.test.consul.state.peerings", + Value: 0, + Labels: []metrics.Label{{Name: "datacenter", Value: "dc1"}}, + }, // --- member --- "consul.usage.test.consul.members.servers;datacenter=dc1": { Name: "consul.usage.test.consul.members.servers", diff --git a/website/content/docs/agent/telemetry.mdx b/website/content/docs/agent/telemetry.mdx index 0e00fa7aec..575f3d7e5b 100644 --- a/website/content/docs/agent/telemetry.mdx +++ b/website/content/docs/agent/telemetry.mdx @@ -389,6 +389,7 @@ This is a full list of metrics emitted by Consul. | `consul.runtime.alloc_bytes` | Measures the number of bytes allocated by the Consul process. This may burst from time to time but should return to a steady state value. | bytes | gauge | | `consul.runtime.heap_objects` | Measures the number of objects allocated on the heap and is a general memory pressure indicator. This may burst from time to time but should return to a steady state value. | number of objects | gauge | | `consul.state.nodes` | Measures the current number of nodes registered with Consul. It is only emitted by Consul servers. Added in v1.9.0. | number of objects | gauge | +| `consul.state.peerings` | Measures the current number of peerings registered with Consul. It is only emitted by Consul servers. Added in v1.13.0. | number of objects | gauge | | `consul.state.services` | Measures the current number of unique services registered with Consul, based on service name. It is only emitted by Consul servers. Added in v1.9.0. | number of objects | gauge | | `consul.state.service_instances` | Measures the current number of unique service instances registered with Consul. It is only emitted by Consul servers. Added in v1.9.0. | number of objects | gauge | | `consul.state.kv_entries` | Measures the current number of unique KV entries written in Consul. It is only emitted by Consul servers. Added in v1.10.3. | number of objects | gauge |