diff --git a/cmd/tetra/metrics/print.go b/cmd/tetra/metrics/print.go index 3afc6442047..281f5763eba 100644 --- a/cmd/tetra/metrics/print.go +++ b/cmd/tetra/metrics/print.go @@ -55,7 +55,18 @@ func New() *cobra.Command { }, } - return metricsmd.NewCmd(nil, nil, map[string]string{}, targets, overrides, initMetrics) + config := &metricsmd.Config{ + Targets: targets, + LabelOverrides: overrides, + InitMetrics: initMetrics, + HeadingLevel: 1, + } + + cmd, err := metricsmd.NewCmd(nil, nil, config) + if err != nil { + slog.Error("failed to create metrics-docs command", "error", err) + } + return cmd } func initMetrics(target string, reg *prometheus.Registry, _ *slog.Logger) error { diff --git a/docs/content/en/docs/reference/metrics.md b/docs/content/en/docs/reference/metrics.md index e7aa3967b4d..8b98aa2c7ce 100644 --- a/docs/content/en/docs/reference/metrics.md +++ b/docs/content/en/docs/reference/metrics.md @@ -5,11 +5,9 @@ description: > using github.com/isovalent/metricstool weight: 4 --- - +## Tetragon Health Metrics -# Tetragon Health Metrics - -## `tetragon_build_info` +### `tetragon_build_info` Build information about tetragon @@ -20,7 +18,7 @@ Build information about tetragon | `modified` | `false` | | `time ` | `2022-05-13T15:54:45Z` | -## `tetragon_data_event_size` +### `tetragon_data_event_size` The size of received data events. @@ -28,7 +26,7 @@ The size of received data events. | ----- | ------ | | `op ` | `bad, ok` | -## `tetragon_data_events_total` +### `tetragon_data_events_total` The number of data events by type. For internal use only. @@ -36,7 +34,7 @@ The number of data events by type. For internal use only. | ----- | ------ | | `event` | `Added, Appended, Bad, Matched, NotMatched, Received` | -## `tetragon_errors_total` +### `tetragon_errors_total` The total number of Tetragon errors. For internal use only. @@ -44,11 +42,11 @@ The total number of Tetragon errors. For internal use only. | ----- | ------ | | `type ` | `event_finalize_process_info_failed, event_missing_process_info, handler_error, process_cache_evicted, process_cache_miss_on_get, process_cache_miss_on_remove, process_pid_tid_mismatch` | -## `tetragon_event_cache_accesses_total` +### `tetragon_event_cache_accesses_total` The total number of Tetragon event cache accesses. For internal use only. -## `tetragon_event_cache_errors_total` +### `tetragon_event_cache_errors_total` The total of errors encountered while fetching process exec information from the cache. @@ -57,7 +55,7 @@ The total of errors encountered while fetching process exec information from the | `error` | `nil_process_pid` | | `event_type` | `PROCESS_EXEC, PROCESS_EXIT, PROCESS_KPROBE, PROCESS_LOADER, PROCESS_TRACEPOINT, PROCESS_UPROBE, RATE_LIMIT_INFO` | -## `tetragon_event_cache_parent_info_errors_total` +### `tetragon_event_cache_parent_info_errors_total` The total of times we failed to fetch cached parent info for a given event type. @@ -65,7 +63,7 @@ The total of times we failed to fetch cached parent info for a given event type. | ----- | ------ | | `event_type` | `PROCESS_EXEC, PROCESS_EXIT, PROCESS_KPROBE, PROCESS_LOADER, PROCESS_TRACEPOINT, PROCESS_UPROBE, RATE_LIMIT_INFO` | -## `tetragon_event_cache_pod_info_errors_total` +### `tetragon_event_cache_pod_info_errors_total` The total of times we failed to fetch cached pod info for a given event type. @@ -73,7 +71,7 @@ The total of times we failed to fetch cached pod info for a given event type. | ----- | ------ | | `event_type` | `PROCESS_EXEC, PROCESS_EXIT, PROCESS_KPROBE, PROCESS_LOADER, PROCESS_TRACEPOINT, PROCESS_UPROBE, RATE_LIMIT_INFO` | -## `tetragon_event_cache_process_info_errors_total` +### `tetragon_event_cache_process_info_errors_total` The total of times we failed to fetch cached process info for a given event type. @@ -81,7 +79,7 @@ The total of times we failed to fetch cached process info for a given event type | ----- | ------ | | `event_type` | `PROCESS_EXEC, PROCESS_EXIT, PROCESS_KPROBE, PROCESS_LOADER, PROCESS_TRACEPOINT, PROCESS_UPROBE, RATE_LIMIT_INFO` | -## `tetragon_event_cache_retries_total` +### `tetragon_event_cache_retries_total` The total number of retries for event caching per entry type. @@ -89,7 +87,7 @@ The total number of retries for event caching per entry type. | ----- | ------ | | `entry_type` | `parent_info, pod_info, process_info` | -## `tetragon_flags_total` +### `tetragon_flags_total` The total number of Tetragon flags. For internal use only. @@ -97,7 +95,7 @@ The total number of Tetragon flags. For internal use only. | ----- | ------ | | `type ` | `auid, clone, errorArgs, errorCWD, errorCgroupID, errorCgroupKn, errorCgroupName, errorCgroupSubsys, errorCgroupSubsysCgrp, errorCgroups, errorFilename, errorPathResolutionCwd, execve, execveat, miss, nocwd, procFS, rootcwd, taskWalk, truncArgs, truncFilename` | -## `tetragon_generic_kprobe_merge_errors_total` +### `tetragon_generic_kprobe_merge_errors_total` The total number of failed attempts to merge a kprobe and kretprobe event. @@ -108,15 +106,15 @@ The total number of failed attempts to merge a kprobe and kretprobe event. | `prev_fn` | `example_kprobe` | | `prev_type` | `enter, exit` | -## `tetragon_generic_kprobe_merge_ok_total` +### `tetragon_generic_kprobe_merge_ok_total` The total number of successful attempts to merge a kprobe and kretprobe event. -## `tetragon_generic_kprobe_merge_pushed_total` +### `tetragon_generic_kprobe_merge_pushed_total` The total number of pushed events for later merge. -## `tetragon_handler_errors_total` +### `tetragon_handler_errors_total` The total number of event handler errors. For internal use only. @@ -125,7 +123,7 @@ The total number of event handler errors. For internal use only. | `error_type` | `event_handler_failed, unknown_opcode` | | `opcode` | `0, 11, 13, 14, 15, 23, 24, 25, 26, 5, 7` | -## `tetragon_handling_latency` +### `tetragon_handling_latency` The latency of handling messages in us. @@ -133,7 +131,7 @@ The latency of handling messages in us. | ----- | ------ | | `op ` | `11, 13, 14, 15, 23, 24, 25, 26, 5, 7` | -## `tetragon_map_errors_total` +### `tetragon_map_errors_total` The total number of entries dropped per LRU map. @@ -141,7 +139,7 @@ The total number of entries dropped per LRU map. | ----- | ------ | | `map ` | `execve_map, tg_execve_joined_info_map` | -## `tetragon_map_in_use_gauge` +### `tetragon_map_in_use_gauge` The total number of in-use entries per map. @@ -150,7 +148,7 @@ The total number of in-use entries per map. | `map ` | `execve_map, tg_execve_joined_info_map` | | `total` | ` 0` | -## `tetragon_missed_events_total` +### `tetragon_missed_events_total` The total number of Tetragon events per type that are failed to sent from the kernel. @@ -158,7 +156,7 @@ The total number of Tetragon events per type that are failed to sent from the ke | ----- | ------ | | `msg_op` | `11, 13, 14, 15, 23, 24, 25, 26, 5, 7` | -## `tetragon_msg_op_total` +### `tetragon_msg_op_total` The total number of times we encounter a given message opcode. For internal use only. @@ -166,11 +164,11 @@ The total number of times we encounter a given message opcode. For internal use | ----- | ------ | | `msg_op` | `11, 13, 14, 15, 23, 24, 25, 26, 5, 7` | -## `tetragon_notify_overflowed_events_total` +### `tetragon_notify_overflowed_events_total` The total number of events dropped because listener buffer was full -## `tetragon_policyfilter_metrics_total` +### `tetragon_policyfilter_metrics_total` Policy filter metrics. For internal use only. @@ -179,7 +177,7 @@ Policy filter metrics. For internal use only. | `op ` | `add, add-container, delete, update` | | `subsys` | `pod-handlers, rthooks` | -## `tetragon_process_loader_stats` +### `tetragon_process_loader_stats` Process Loader event statistics. For internal use only. @@ -187,31 +185,31 @@ Process Loader event statistics. For internal use only. | ----- | ------ | | `count` | `LoaderReceived, LoaderResolvedImm, LoaderResolvedRetry` | -## `tetragon_ratelimit_dropped_total` +### `tetragon_ratelimit_dropped_total` The total number of rate limit Tetragon drops -## `tetragon_ringbuf_perf_event_errors_total` +### `tetragon_ringbuf_perf_event_errors_total` The total number of errors when reading the Tetragon ringbuf. -## `tetragon_ringbuf_perf_event_lost_total` +### `tetragon_ringbuf_perf_event_lost_total` The total number of Tetragon ringbuf perf events lost. -## `tetragon_ringbuf_perf_event_received_total` +### `tetragon_ringbuf_perf_event_received_total` The total number of Tetragon ringbuf perf events received. -## `tetragon_ringbuf_queue_lost_total` +### `tetragon_ringbuf_queue_lost_total` The total number of Tetragon events ring buffer queue lost. -## `tetragon_ringbuf_queue_received_total` +### `tetragon_ringbuf_queue_received_total` The total number of Tetragon events ring buffer queue received. -## `tetragon_tracingpolicy_loaded` +### `tetragon_tracingpolicy_loaded` The number of loaded tracing policy by state. @@ -219,7 +217,7 @@ The number of loaded tracing policy by state. | ----- | ------ | | `state` | `disabled, enabled, error, load_error` | -## `tetragon_watcher_errors_total` +### `tetragon_watcher_errors_total` The total number of errors for a given watcher type. @@ -228,7 +226,7 @@ The total number of errors for a given watcher type. | `error` | `failed_to_get_pod` | | `watcher` | ` k8s` | -## `tetragon_watcher_events_total` +### `tetragon_watcher_events_total` The total number of events for a given watcher type. @@ -236,19 +234,17 @@ The total number of events for a given watcher type. | ----- | ------ | | `watcher` | ` k8s` | - - -# Tetragon Resources Metrics +## Tetragon Resources Metrics -## `go_gc_duration_seconds` +### `go_gc_duration_seconds` A summary of the pause duration of garbage collection cycles. -## `go_goroutines` +### `go_goroutines` Number of goroutines that currently exist. -## `go_info` +### `go_info` Information about the Go environment. @@ -256,135 +252,133 @@ Information about the Go environment. | ----- | ------ | | `version` | `go1.22.0` | -## `go_memstats_alloc_bytes` +### `go_memstats_alloc_bytes` Number of bytes allocated and still in use. -## `go_memstats_alloc_bytes_total` +### `go_memstats_alloc_bytes_total` Total number of bytes allocated, even if freed. -## `go_memstats_buck_hash_sys_bytes` +### `go_memstats_buck_hash_sys_bytes` Number of bytes used by the profiling bucket hash table. -## `go_memstats_frees_total` +### `go_memstats_frees_total` Total number of frees. -## `go_memstats_gc_sys_bytes` +### `go_memstats_gc_sys_bytes` Number of bytes used for garbage collection system metadata. -## `go_memstats_heap_alloc_bytes` +### `go_memstats_heap_alloc_bytes` Number of heap bytes allocated and still in use. -## `go_memstats_heap_idle_bytes` +### `go_memstats_heap_idle_bytes` Number of heap bytes waiting to be used. -## `go_memstats_heap_inuse_bytes` +### `go_memstats_heap_inuse_bytes` Number of heap bytes that are in use. -## `go_memstats_heap_objects` +### `go_memstats_heap_objects` Number of allocated objects. -## `go_memstats_heap_released_bytes` +### `go_memstats_heap_released_bytes` Number of heap bytes released to OS. -## `go_memstats_heap_sys_bytes` +### `go_memstats_heap_sys_bytes` Number of heap bytes obtained from system. -## `go_memstats_last_gc_time_seconds` +### `go_memstats_last_gc_time_seconds` Number of seconds since 1970 of last garbage collection. -## `go_memstats_lookups_total` +### `go_memstats_lookups_total` Total number of pointer lookups. -## `go_memstats_mallocs_total` +### `go_memstats_mallocs_total` Total number of mallocs. -## `go_memstats_mcache_inuse_bytes` +### `go_memstats_mcache_inuse_bytes` Number of bytes in use by mcache structures. -## `go_memstats_mcache_sys_bytes` +### `go_memstats_mcache_sys_bytes` Number of bytes used for mcache structures obtained from system. -## `go_memstats_mspan_inuse_bytes` +### `go_memstats_mspan_inuse_bytes` Number of bytes in use by mspan structures. -## `go_memstats_mspan_sys_bytes` +### `go_memstats_mspan_sys_bytes` Number of bytes used for mspan structures obtained from system. -## `go_memstats_next_gc_bytes` +### `go_memstats_next_gc_bytes` Number of heap bytes when next garbage collection will take place. -## `go_memstats_other_sys_bytes` +### `go_memstats_other_sys_bytes` Number of bytes used for other system allocations. -## `go_memstats_stack_inuse_bytes` +### `go_memstats_stack_inuse_bytes` Number of bytes in use by the stack allocator. -## `go_memstats_stack_sys_bytes` +### `go_memstats_stack_sys_bytes` Number of bytes obtained from system for stack allocator. -## `go_memstats_sys_bytes` +### `go_memstats_sys_bytes` Number of bytes obtained from system. -## `go_threads` +### `go_threads` Number of OS threads created. -## `process_cpu_seconds_total` +### `process_cpu_seconds_total` Total user and system CPU time spent in seconds. -## `process_max_fds` +### `process_max_fds` Maximum number of open file descriptors. -## `process_open_fds` +### `process_open_fds` Number of open file descriptors. -## `process_resident_memory_bytes` +### `process_resident_memory_bytes` Resident memory size in bytes. -## `process_start_time_seconds` +### `process_start_time_seconds` Start time of the process since unix epoch in seconds. -## `process_virtual_memory_bytes` +### `process_virtual_memory_bytes` Virtual memory size in bytes. -## `process_virtual_memory_max_bytes` +### `process_virtual_memory_max_bytes` Maximum amount of virtual memory available in bytes. - - -# Tetragon Events Metrics +## Tetragon Events Metrics -## `tetragon_events_total` +### `tetragon_events_total` The total number of Tetragon events @@ -396,7 +390,7 @@ The total number of Tetragon events | `type ` | `PROCESS_EXEC, PROCESS_EXIT, PROCESS_KPROBE, PROCESS_LOADER, PROCESS_TRACEPOINT, PROCESS_UPROBE, RATE_LIMIT_INFO` | | `workload` | `example-workload` | -## `tetragon_policy_events_total` +### `tetragon_policy_events_total` Policy events calls observed. @@ -409,7 +403,7 @@ Policy events calls observed. | `policy` | `example-tracingpolicy` | | `workload` | `example-workload` | -## `tetragon_syscalls_total` +### `tetragon_syscalls_total` System calls observed. diff --git a/go.mod b/go.mod index 3d1ab5b0913..49277d8e58d 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/iancoleman/strcase v0.3.0 - github.com/isovalent/metricstool v0.0.0-20240220124724-285815580016 + github.com/isovalent/metricstool v0.0.0-20240301011405-23fc556a01bd github.com/jpillora/longestcommon v0.0.0-20161227235612-adb9d91ee629 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mennanov/fieldmask-utils v1.1.0 diff --git a/go.sum b/go.sum index ce51a7134bf..22ace71f7ca 100644 --- a/go.sum +++ b/go.sum @@ -335,8 +335,8 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/isovalent/metricstool v0.0.0-20240220124724-285815580016 h1:8kTfM4TIcCeKUfD0ct45SHLUgIqBB391be1HuyjaKVc= -github.com/isovalent/metricstool v0.0.0-20240220124724-285815580016/go.mod h1:ol80lPphlGYFS16mc54bPVudTT8GkIaHwRMiUuya0sY= +github.com/isovalent/metricstool v0.0.0-20240301011405-23fc556a01bd h1:kxGyqpr4uB94wkfS87C65JXTboaMFy0585PQl+y7/fE= +github.com/isovalent/metricstool v0.0.0-20240301011405-23fc556a01bd/go.mod h1:ol80lPphlGYFS16mc54bPVudTT8GkIaHwRMiUuya0sY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= diff --git a/vendor/github.com/isovalent/metricstool/pkg/metricsmd/config.go b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/config.go new file mode 100644 index 00000000000..96d8f8d1305 --- /dev/null +++ b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/config.go @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Isovalent Inc. + +package metricsmd + +import ( + "fmt" + "log/slog" + + "github.com/prometheus/client_golang/prometheus" +) + +type LabelValues struct { + Label string + Values []string +} + +type LabelOverrides struct { + Metric string + Overrides []LabelValues +} + +type Config struct { + CobraAnnotations map[string]string + Targets map[string]string // cli argument -> docs header + LabelOverrides []LabelOverrides + InitMetrics func(target string, reg *prometheus.Registry, log *slog.Logger) error + AutogeneratedComment bool + HeadingLevel int // must be between 0 and 4 +} + +func validateConfig(config *Config) error { + if config.Targets == nil { + return fmt.Errorf("config.Targets must be set") + } + if config.InitMetrics == nil { + return fmt.Errorf("config.InitMetrics must be set") + } + if config.HeadingLevel < 0 || config.HeadingLevel > 4 { + return fmt.Errorf("config.HeadingLevel must be between 0 and 4") + } + return nil +} diff --git a/vendor/github.com/isovalent/metricstool/pkg/metricsmd/generate.go b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/generate.go index 48573c1e9c6..5dfe9199aef 100644 --- a/vendor/github.com/isovalent/metricstool/pkg/metricsmd/generate.go +++ b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/generate.go @@ -13,7 +13,7 @@ import ( ) // Generate -func Generate(reg *prometheus.Registry, w io.Writer, labelOverrides []LabelOverrides) error { +func Generate(reg *prometheus.Registry, w io.Writer, config *Config) error { metricsFamilies, err := reg.Gather() if err != nil { return err @@ -24,7 +24,11 @@ func Generate(reg *prometheus.Registry, w io.Writer, labelOverrides []LabelOverr for _, metric := range metricsFamilies { // Include the metric name and help text. - io.WriteString(w, fmt.Sprintf("## `%s`\n\n", metric.GetName())) + h := "##" + for i := 0; i < config.HeadingLevel; i++ { + h += "#" + } + io.WriteString(w, fmt.Sprintf("%s `%s`\n\n", h, metric.GetName())) io.WriteString(w, fmt.Sprintf("%s\n\n", metric.GetHelp())) // The rest is generating a list of label names and values @@ -42,12 +46,14 @@ func Generate(reg *prometheus.Registry, w io.Writer, labelOverrides []LabelOverr labelsToValues[label.GetName()] = make(map[string]struct{}) } // Add the value to the set of values for this label - labelsToValues[label.GetName()][label.GetValue()] = struct{}{} + if val := label.GetValue(); val != "" { + labelsToValues[label.GetName()][val] = struct{}{} + } } } // Support overriding the values of labels, in case they're not suitable for docs. - for _, override := range labelOverrides { + for _, override := range config.LabelOverrides { if override.Metric != metric.GetName() { continue } @@ -91,13 +97,3 @@ func Generate(reg *prometheus.Registry, w io.Writer, labelOverrides []LabelOverr } return nil } - -type LabelValues struct { - Label string - Values []string -} - -type LabelOverrides struct { - Metric string - Overrides []LabelValues -} diff --git a/vendor/github.com/isovalent/metricstool/pkg/metricsmd/print.go b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/print.go index c614e8b3c3e..2f771aef1ef 100644 --- a/vendor/github.com/isovalent/metricstool/pkg/metricsmd/print.go +++ b/vendor/github.com/isovalent/metricstool/pkg/metricsmd/print.go @@ -16,21 +16,19 @@ import ( "github.com/spf13/viper" ) -type targetToHeader map[string]string - -type initMetricsFunc func(target string, reg *prometheus.Registry, log *slog.Logger) error - // NewCmd creates a Cobra command for generating metrics reference docs. // It's intended to be used as an add-on to applications that have a Cobra CLI // and expose Prometheus metrics. -func NewCmd(vp *viper.Viper, log *slog.Logger, annotations map[string]string, - targets targetToHeader, overrides []LabelOverrides, initMetrics initMetricsFunc, -) *cobra.Command { +func NewCmd(vp *viper.Viper, log *slog.Logger, config *Config) (*cobra.Command, error) { + err := validateConfig(config) + if err != nil { + return nil, err + } cmd := &cobra.Command{ Use: "metrics-docs", Hidden: true, - Annotations: annotations, - ValidArgs: maps.Keys(targets), + Annotations: config.CobraAnnotations, + ValidArgs: maps.Keys(config.Targets), Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), PreRunE: func(cmd *cobra.Command, _ []string) error { if vp != nil { @@ -45,18 +43,24 @@ func NewCmd(vp *viper.Viper, log *slog.Logger, annotations map[string]string, target := args[0] reg := prometheus.NewRegistry() - err := initMetrics(target, reg, log) + err := config.InitMetrics(target, reg, log) if err != nil { return err } var b bytes.Buffer - // Comment to inform people this file is autogenerated. - b.WriteString("\n\n") + if config.AutogeneratedComment { + // Comment to inform people this file is autogenerated. + b.WriteString("\n\n") + } // Document title - b.WriteString(fmt.Sprintf("# %s Metrics\n\n", targets[target])) + h := "#" + for i := 0; i < config.HeadingLevel; i++ { + h += "#" + } + b.WriteString(fmt.Sprintf("%s %s Metrics\n\n", h, config.Targets[target])) // Generate metrics reference - err = Generate(reg, &b, overrides) + err = Generate(reg, &b, config) if err != nil { return err } @@ -65,5 +69,5 @@ func NewCmd(vp *viper.Viper, log *slog.Logger, annotations map[string]string, return nil }, } - return cmd + return cmd, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index b06c5581254..f55a0f821e2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -578,7 +578,7 @@ github.com/imdario/mergo # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap -# github.com/isovalent/metricstool v0.0.0-20240220124724-285815580016 +# github.com/isovalent/metricstool v0.0.0-20240301011405-23fc556a01bd ## explicit; go 1.22.0 github.com/isovalent/metricstool/pkg/metricsmd # github.com/josharian/intern v1.0.0