Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor metrics doc generator #11467

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 4 additions & 12 deletions docs/metrics.md
@@ -1,14 +1,5 @@
<!--
This is an auto-generated file.
PLEASE DO NOT EDIT THIS FILE.
See "Developing new metrics" below how to generate this file
-->
# Kubevirt metrics

# KubeVirt metrics
This document aims to help users that are not familiar with all metrics exposed by different KubeVirt components.
All metrics documented here are auto-generated by the utility tool `tools/doc-generator` and reflects exactly what is being exposed.

## KubeVirt Metrics List
### kubevirt_info
Version information.

Expand Down Expand Up @@ -268,6 +259,7 @@ Returns the labels of the persistent volume claims that are used for restoring v
Amount of active VNC connections, broken down by namespace and vmi name. Type: Gauge.

## Developing new metrics
After developing new metrics or changing old ones, please run `make generate` to regenerate this document.

If you feel that the new metric doesn't follow these rules, please change `doc-generator` with your needs.
All metrics documented here are auto-generated and reflect exactly what is being
exposed. After developing new metrics or changing old ones please regenerate
this document.
3 changes: 1 addition & 2 deletions hack/generate.sh
Expand Up @@ -140,8 +140,7 @@ ${KUBEVIRT_DIR}/tools/openapispec/openapispec --dump-api-spec-path ${KUBEVIRT_DI
(cd ${KUBEVIRT_DIR}/tools/doc-generator/ && go_build)
(
cd ${KUBEVIRT_DIR}/docs
${KUBEVIRT_DIR}/tools/doc-generator/doc-generator
mv newmetrics.md metrics.md
${KUBEVIRT_DIR}/tools/doc-generator/doc-generator >metrics.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
${KUBEVIRT_DIR}/tools/doc-generator/doc-generator >metrics.md
${KUBEVIRT_DIR}/tools/doc-generator/doc-generator > metrics.md

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this one was fixed by make generate I did use a space in the beginning

)

rm -f ${KUBEVIRT_DIR}/manifests/generated/*
Expand Down
3 changes: 3 additions & 0 deletions tools/doc-generator/BUILD.bazel
Expand Up @@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = [
"MetricsCollector.go",
"doc-generator.go",
"fakeDomainCollector.go",
],
Expand All @@ -19,7 +20,9 @@ go_library(
"//pkg/virt-launcher/virtwrap/statsconv:go_default_library",
"//pkg/virt-launcher/virtwrap/statsconv/util:go_default_library",
"//staging/src/kubevirt.io/api/core/v1:go_default_library",
"//vendor/github.com/machadovilaca/operator-observability/pkg/docs:go_default_library",
"//vendor/github.com/machadovilaca/operator-observability/pkg/operatormetrics:go_default_library",
"//vendor/github.com/machadovilaca/operator-observability/pkg/operatorrules:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/libvirt.org/go/libvirt:go_default_library",
],
Expand Down
119 changes: 119 additions & 0 deletions tools/doc-generator/MetricsCollector.go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tools/doc-generator/metrics_collector.go

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do wee need to use a metrics collector? can you use the list methods from each component monitoring package?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we query the end point and add metrics manually that's why I asked if we can avoid that.

@@ -0,0 +1,119 @@
package main

import (
"bufio"
"fmt"
"io"
"sort"
"strings"

domainstats "kubevirt.io/kubevirt/pkg/monitoring/domainstats/prometheus" // import for prometheus metrics
_ "kubevirt.io/kubevirt/pkg/virt-controller/watch"
)

type metric struct {
name string
description string
mType string
}

type metricList []metric

func getMetricsNotIncludeInEndpointByDefault() metricList {
metrics := metricList{
{
name: domainstats.MigrateVmiDataProcessedMetricName,
description: "The total Guest OS data processed and migrated to the new VM.",
mType: "Gauge",
},
{
name: domainstats.MigrateVmiDataRemainingMetricName,
description: "The remaining guest OS data to be migrated to the new VM.",
mType: "Gauge",
},
{
name: domainstats.MigrateVmiDirtyMemoryRateMetricName,
description: "The rate of memory being dirty in the Guest OS.",
mType: "Gauge",
},
{
name: domainstats.MigrateVmiMemoryTransferRateMetricName,
description: "The rate at which the memory is being transferred.",
mType: "Gauge",
},
}

return metrics
}

// Len implements sort.Interface.Len
func (m metricList) Len() int {
return len(m)
}

// Less implements sort.Interface.Less
func (m metricList) Less(i, j int) bool {
return m[i].name < m[j].name
}

// Swap implements sort.Interface.Swap
func (m metricList) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}

func parseMetricDesc(line string) (string, string) {
split := strings.Split(line, " ")
name := split[2]
split[3] = strings.Title(split[3])
description := strings.Join(split[3:], " ")
return name, description
}

func parseMetricType(scan *bufio.Scanner, name string) string {
for scan.Scan() {
typeLine := scan.Text()
if strings.HasPrefix(typeLine, "# TYPE ") {
split := strings.Split(typeLine, " ")
if split[2] == name {
return strings.Title(split[3])
}
}
}
return ""
}

func parseVirtMetrics(r io.Reader, metrics *metricList) error {
scan := bufio.NewScanner(r)
for scan.Scan() {
helpLine := scan.Text()
if strings.HasPrefix(helpLine, "# HELP ") {
if strings.Contains(helpLine, "kubevirt_") {
metName, metDesc := parseMetricDesc(helpLine)
metType := parseMetricType(scan, metName)
*metrics = append(*metrics, metric{name: metName, description: metDesc, mType: metType})
}
}
}

if scan.Err() != nil {
return fmt.Errorf("failed to parse metrics from prometheus endpoint, %w", scan.Err())
}

sort.Sort(metrics)

// remove duplicates
for i := 0; i < len(*metrics)-1; i++ {
if (*metrics)[i].name == (*metrics)[i+1].name {
*metrics = append((*metrics)[:i], (*metrics)[i+1:]...)
i--
}
}

return nil
}

func checkError(err error) {
if err != nil {
panic(err)
}
}