From a0ba88d4ea521b98ca9c7b42f43d78d7b3c6f052 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Fri, 7 Apr 2023 23:53:14 -0400 Subject: [PATCH] test: port prometheus test to Go --- cmd/ipfs/daemon.go | 6 +- go.mod | 2 +- test/cli/prometheus_test.go | 277 ++++++++++++++++++++++++++++++++++++ test/cli/testutils/set.go | 11 ++ 4 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 test/cli/prometheus_test.go create mode 100644 test/cli/testutils/set.go diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index daff0b9eb61..4c1e3da4fb4 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -437,7 +437,11 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment default: return fmt.Errorf("unrecognized routing option: %s", routingOption) } - view.Register(dhtmetrics.DefaultViews...) + + err = view.Register(dhtmetrics.DefaultViews...) + if err != nil { + return fmt.Errorf("registering Prometheus view for DHT: %w", err) + } agentVersionSuffixString, _ := req.Options[agentVersionSuffix].(string) if agentVersionSuffixString != "" { diff --git a/go.mod b/go.mod index 95f326b14b7..de6f185bf7c 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/common v0.42.0 github.com/stretchr/testify v1.8.2 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tidwall/gjson v1.14.4 @@ -179,7 +180,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect github.com/quic-go/qpack v0.4.0 // indirect diff --git a/test/cli/prometheus_test.go b/test/cli/prometheus_test.go new file mode 100644 index 00000000000..db02f500d69 --- /dev/null +++ b/test/cli/prometheus_test.go @@ -0,0 +1,277 @@ +package cli + +import ( + "strings" + "testing" + "time" + + "github.com/ipfs/kubo/config" + "github.com/ipfs/kubo/test/cli/harness" + "github.com/ipfs/kubo/test/cli/testutils" + "github.com/prometheus/common/expfmt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var metricsRcmgrFamilies = map[string]bool{ + "libp2p_rcmgr_memory_allocations_allowed_total": true, + "libp2p_rcmgr_memory_allocations_blocked_total": true, + "libp2p_rcmgr_peer_blocked_total": true, + "libp2p_rcmgr_peers_allowed_total": true, +} + +var metricsDefaultFamilies = map[string]bool{ + "flatfs_datastore_batchcommit_errors_total": true, + "flatfs_datastore_batchcommit_latency_seconds": true, + "flatfs_datastore_batchcommit_total": true, + "flatfs_datastore_batchdelete_errors_total": true, + "flatfs_datastore_batchdelete_latency_seconds": true, + "flatfs_datastore_batchdelete_total": true, + "flatfs_datastore_batchput_errors_total": true, + "flatfs_datastore_batchput_latency_seconds": true, + "flatfs_datastore_batchput_size_bytes": true, + "flatfs_datastore_batchput_total": true, + "flatfs_datastore_check_errors_total": true, + "flatfs_datastore_check_latency_seconds": true, + "flatfs_datastore_check_total": true, + "flatfs_datastore_delete_errors_total": true, + "flatfs_datastore_delete_latency_seconds": true, + "flatfs_datastore_delete_total": true, + "flatfs_datastore_du_errors_total": true, + "flatfs_datastore_du_latency_seconds": true, + "flatfs_datastore_du_total": true, + "flatfs_datastore_gc_errors_total": true, + "flatfs_datastore_gc_latency_seconds": true, + "flatfs_datastore_gc_total": true, + "flatfs_datastore_get_errors_total": true, + "flatfs_datastore_get_latency_seconds": true, + "flatfs_datastore_get_size_bytes": true, + "flatfs_datastore_get_total": true, + "flatfs_datastore_getsize_errors_total": true, + "flatfs_datastore_getsize_latency_seconds": true, + "flatfs_datastore_getsize_total": true, + "flatfs_datastore_has_errors_total": true, + "flatfs_datastore_has_latency_seconds": true, + "flatfs_datastore_has_total": true, + "flatfs_datastore_put_errors_total": true, + "flatfs_datastore_put_latency_seconds": true, + "flatfs_datastore_put_size_bytes": true, + "flatfs_datastore_put_total": true, + "flatfs_datastore_query_errors_total": true, + "flatfs_datastore_query_latency_seconds": true, + "flatfs_datastore_query_total": true, + "flatfs_datastore_scrub_errors_total": true, + "flatfs_datastore_scrub_latency_seconds": true, + "flatfs_datastore_scrub_total": true, + "flatfs_datastore_sync_errors_total": true, + "flatfs_datastore_sync_latency_seconds": true, + "flatfs_datastore_sync_total": true, + "go_gc_duration_seconds": true, + "go_goroutines": true, + "go_info": true, + "go_memstats_alloc_bytes": true, + "go_memstats_alloc_bytes_total": true, + "go_memstats_buck_hash_sys_bytes": true, + "go_memstats_frees_total": true, + "go_memstats_gc_sys_bytes": true, + "go_memstats_heap_alloc_bytes": true, + "go_memstats_heap_idle_bytes": true, + "go_memstats_heap_inuse_bytes": true, + "go_memstats_heap_objects": true, + "go_memstats_heap_released_bytes": true, + "go_memstats_heap_sys_bytes": true, + "go_memstats_last_gc_time_seconds": true, + "go_memstats_lookups_total": true, + "go_memstats_mallocs_total": true, + "go_memstats_mcache_inuse_bytes": true, + "go_memstats_mcache_sys_bytes": true, + "go_memstats_mspan_inuse_bytes": true, + "go_memstats_mspan_sys_bytes": true, + "go_memstats_next_gc_bytes": true, + "go_memstats_other_sys_bytes": true, + "go_memstats_stack_inuse_bytes": true, + "go_memstats_stack_sys_bytes": true, + "go_memstats_sys_bytes": true, + "go_threads": true, + "ipfs_bitswap_active_block_tasks": true, + "ipfs_bitswap_active_tasks": true, + "ipfs_bitswap_pending_block_tasks": true, + "ipfs_bitswap_pending_tasks": true, + "ipfs_bitswap_recv_all_blocks_bytes": true, + "ipfs_bitswap_recv_dup_blocks_bytes": true, + "ipfs_bitswap_send_times": true, + "ipfs_bitswap_sent_all_blocks_bytes": true, + "ipfs_bitswap_want_blocks_total": true, + "ipfs_bitswap_wantlist_total": true, + "ipfs_bs_cache_arc_hits_total": true, + "ipfs_bs_cache_arc_total": true, + "ipfs_fsrepo_datastore_batchcommit_errors_total": true, + "ipfs_fsrepo_datastore_batchcommit_latency_seconds": true, + "ipfs_fsrepo_datastore_batchcommit_total": true, + "ipfs_fsrepo_datastore_batchdelete_errors_total": true, + "ipfs_fsrepo_datastore_batchdelete_latency_seconds": true, + "ipfs_fsrepo_datastore_batchdelete_total": true, + "ipfs_fsrepo_datastore_batchput_errors_total": true, + "ipfs_fsrepo_datastore_batchput_latency_seconds": true, + "ipfs_fsrepo_datastore_batchput_size_bytes": true, + "ipfs_fsrepo_datastore_batchput_total": true, + "ipfs_fsrepo_datastore_check_errors_total": true, + "ipfs_fsrepo_datastore_check_latency_seconds": true, + "ipfs_fsrepo_datastore_check_total": true, + "ipfs_fsrepo_datastore_delete_errors_total": true, + "ipfs_fsrepo_datastore_delete_latency_seconds": true, + "ipfs_fsrepo_datastore_delete_total": true, + "ipfs_fsrepo_datastore_du_errors_total": true, + "ipfs_fsrepo_datastore_du_latency_seconds": true, + "ipfs_fsrepo_datastore_du_total": true, + "ipfs_fsrepo_datastore_gc_errors_total": true, + "ipfs_fsrepo_datastore_gc_latency_seconds": true, + "ipfs_fsrepo_datastore_gc_total": true, + "ipfs_fsrepo_datastore_get_errors_total": true, + "ipfs_fsrepo_datastore_get_latency_seconds": true, + "ipfs_fsrepo_datastore_get_size_bytes": true, + "ipfs_fsrepo_datastore_get_total": true, + "ipfs_fsrepo_datastore_getsize_errors_total": true, + "ipfs_fsrepo_datastore_getsize_latency_seconds": true, + "ipfs_fsrepo_datastore_getsize_total": true, + "ipfs_fsrepo_datastore_has_errors_total": true, + "ipfs_fsrepo_datastore_has_latency_seconds": true, + "ipfs_fsrepo_datastore_has_total": true, + "ipfs_fsrepo_datastore_put_errors_total": true, + "ipfs_fsrepo_datastore_put_latency_seconds": true, + "ipfs_fsrepo_datastore_put_size_bytes": true, + "ipfs_fsrepo_datastore_put_total": true, + "ipfs_fsrepo_datastore_query_errors_total": true, + "ipfs_fsrepo_datastore_query_latency_seconds": true, + "ipfs_fsrepo_datastore_query_total": true, + "ipfs_fsrepo_datastore_scrub_errors_total": true, + "ipfs_fsrepo_datastore_scrub_latency_seconds": true, + "ipfs_fsrepo_datastore_scrub_total": true, + "ipfs_fsrepo_datastore_sync_errors_total": true, + "ipfs_fsrepo_datastore_sync_latency_seconds": true, + "ipfs_fsrepo_datastore_sync_total": true, + "ipfs_http_request_duration_seconds": true, + "ipfs_http_request_size_bytes": true, + "ipfs_http_requests_total": true, + "ipfs_http_response_size_bytes": true, + "ipfs_info": true, + "leveldb_datastore_batchcommit_errors_total": true, + "leveldb_datastore_batchcommit_latency_seconds": true, + "leveldb_datastore_batchcommit_total": true, + "leveldb_datastore_batchdelete_errors_total": true, + "leveldb_datastore_batchdelete_latency_seconds": true, + "leveldb_datastore_batchdelete_total": true, + "leveldb_datastore_batchput_errors_total": true, + "leveldb_datastore_batchput_latency_seconds": true, + "leveldb_datastore_batchput_size_bytes": true, + "leveldb_datastore_batchput_total": true, + "leveldb_datastore_check_errors_total": true, + "leveldb_datastore_check_latency_seconds": true, + "leveldb_datastore_check_total": true, + "leveldb_datastore_delete_errors_total": true, + "leveldb_datastore_delete_latency_seconds": true, + "leveldb_datastore_delete_total": true, + "leveldb_datastore_du_errors_total": true, + "leveldb_datastore_du_latency_seconds": true, + "leveldb_datastore_du_total": true, + "leveldb_datastore_gc_errors_total": true, + "leveldb_datastore_gc_latency_seconds": true, + "leveldb_datastore_gc_total": true, + "leveldb_datastore_get_errors_total": true, + "leveldb_datastore_get_latency_seconds": true, + "leveldb_datastore_get_size_bytes": true, + "leveldb_datastore_get_total": true, + "leveldb_datastore_getsize_errors_total": true, + "leveldb_datastore_getsize_latency_seconds": true, + "leveldb_datastore_getsize_total": true, + "leveldb_datastore_has_errors_total": true, + "leveldb_datastore_has_latency_seconds": true, + "leveldb_datastore_has_total": true, + "leveldb_datastore_put_errors_total": true, + "leveldb_datastore_put_latency_seconds": true, + "leveldb_datastore_put_size_bytes": true, + "leveldb_datastore_put_total": true, + "leveldb_datastore_query_errors_total": true, + "leveldb_datastore_query_latency_seconds": true, + "leveldb_datastore_query_total": true, + "leveldb_datastore_scrub_errors_total": true, + "leveldb_datastore_scrub_latency_seconds": true, + "leveldb_datastore_scrub_total": true, + "leveldb_datastore_sync_errors_total": true, + "leveldb_datastore_sync_latency_seconds": true, + "leveldb_datastore_sync_total": true, + "libp2p_autonat_next_probe_timestamp": true, + "libp2p_autonat_reachability_status": true, + "libp2p_autonat_reachability_status_confidence": true, + "libp2p_autorelay_candidate_loop_state": true, + "libp2p_autorelay_candidates_circuit_v2_support_total": true, + "libp2p_autorelay_desired_reservations": true, + "libp2p_autorelay_relay_addresses_count": true, + "libp2p_autorelay_relay_addresses_updated_total": true, + "libp2p_autorelay_reservation_requests_outcome_total": true, + "libp2p_autorelay_reservations_closed_total": true, + "libp2p_autorelay_reservations_opened_total": true, + "libp2p_autorelay_status": true, + "libp2p_eventbus_events_emitted_total": true, + "libp2p_eventbus_subscriber_event_queued": true, + "libp2p_eventbus_subscriber_queue_full": true, + "libp2p_eventbus_subscriber_queue_length": true, + "libp2p_eventbus_subscribers_total": true, + "libp2p_identify_addrs_count": true, + "libp2p_identify_addrs_received": true, + "libp2p_identify_identify_pushes_triggered_total": true, + "libp2p_identify_protocols_count": true, + "libp2p_identify_protocols_received": true, + "libp2p_relaysvc_connection_duration_seconds": true, + "libp2p_relaysvc_data_transferred_bytes_total": true, + "libp2p_relaysvc_status": true, +} + +func TestPrometheusMetrics(t *testing.T) { + fetchMetricFamilies := func(n *harness.Node) map[string]bool { + resp := n.APIClient().Get("/debug/metrics/prometheus") + parser := &expfmt.TextParser{} + fams, err := parser.TextToMetricFamilies(strings.NewReader(resp.Body)) + require.NoError(t, err) + names := map[string]bool{} + for k := range fams { + names[k] = true + } + return names + } + + assertMetricsEventuallyContainOnly := func(n *harness.Node, m map[string]bool) { + missing := &[]string{} + assert.Eventuallyf(t, func() bool { + *missing = make([]string, 0) + fams := fetchMetricFamilies(n) + for fam := range m { + _, ok := fams[fam] + if !ok { + *missing = append(*missing, fam) + } + } + if len(*missing) > 0 { + return false + } + return len(fams) == len(m) + }, 20*time.Second, 100*time.Millisecond, "expected metrics: %v", missing) + } + + t.Run("default configuration", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + expectedFams := testutils.SetUnion(metricsDefaultFamilies, metricsRcmgrFamilies) + assertMetricsEventuallyContainOnly(node, expectedFams) + }) + + t.Run("resource manager disabled, should not contain rcmgr metrics", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init() + node.UpdateConfig(func(cfg *config.Config) { + cfg.Swarm.ResourceMgr.Enabled = config.False + }) + node.StartDaemon() + assertMetricsEventuallyContainOnly(node, metricsDefaultFamilies) + }) +} diff --git a/test/cli/testutils/set.go b/test/cli/testutils/set.go new file mode 100644 index 00000000000..d40929afce4 --- /dev/null +++ b/test/cli/testutils/set.go @@ -0,0 +1,11 @@ +package testutils + +func SetUnion[T comparable](sets ...map[T]bool) map[T]bool { + newM := map[T]bool{} + for _, s := range sets { + for k, v := range s { + newM[k] = v + } + } + return newM +}