Skip to content

Commit

Permalink
Follow up for Add automated documentation for metrics (#6588)
Browse files Browse the repository at this point in the history
-Use go template in metricsdocs.go

- Add condition to the log messages
- Update the logs messages to use `and monitoring` only when needed.

Signed-off-by: Aviv Litman <[email protected]>
  • Loading branch information
avlitman authored Oct 24, 2023
1 parent 46e04a1 commit 034aef6
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 273 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import (
"github.com/operator-framework/operator-sdk/hack/generate/samples/internal/pkg"
)

// Memcached defines the Memcached Sample in GO using webhooks and monitoring code
// monitoringString is appended to logs and error messages to signify the inclusion of monitoring
const monitoringString = " and monitoring"

// Memcached defines the Memcached Sample in GO using webhooks or webhooks and monitoring code
type Memcached struct {
ctx *pkg.SampleContext
}
Expand All @@ -39,25 +42,36 @@ var prometheusAPIVersion = "v0.59.0"
// GenerateSample will call all actions to create the directory and generate the sample
// Note that it should NOT be called in the e2e tests.
func GenerateSample(binaryPath, samplesPath string) {
log.Infof("starting to generate Go memcached sample with webhooks and metrics documentation")
ctx, err := pkg.NewSampleContext(binaryPath, filepath.Join(samplesPath, "memcached-operator"), "GO111MODULE=on")
pkg.CheckError("generating Go memcached with webhooks and metrics documentation context", err)
generateWithMonitoring = strings.HasSuffix(samplesPath, "monitoring")

logInfo := "starting to generate Go memcached sample with webhooks"
errorInfo := "generating Go memcached with context: webhooks"

generateWithMonitoring = false
if strings.HasSuffix(samplesPath, "monitoring") {
generateWithMonitoring = true
if generateWithMonitoring {
logInfo += monitoringString
errorInfo += monitoringString
}

log.Infof(logInfo)
ctx, err := pkg.NewSampleContext(binaryPath, filepath.Join(samplesPath, "memcached-operator"), "GO111MODULE=on")
pkg.CheckError(errorInfo, err)

memcached := Memcached{&ctx}
memcached.Prepare()
memcached.Run()
}

// Prepare the Context for the Memcached with webhooks and metrics documentation Go Sample
// Prepare the Context for the Memcached with webhooks or with webhooks and monitoring Go Sample
// Note that sample directory will be re-created and the context data for the sample
// will be set such as the domain and GVK.
func (mh *Memcached) Prepare() {
log.Infof("destroying directory for Memcached with webhooks and metrics documentation Go samples")
logInfo := "destroying directory for Go Memcached sample with webhooks"

if generateWithMonitoring {
logInfo += monitoringString
}

log.Infof(logInfo)
mh.ctx.Destroy()

log.Infof("creating directory")
Expand All @@ -71,7 +85,7 @@ func (mh *Memcached) Prepare() {
mh.ctx.Kind = "Memcached"
}

// Run the steps to create the Memcached with metrics and webhooks Go Sample
// Run the steps to create the Memcached with webhooks or with webhooks and monitoring Go Sample
func (mh *Memcached) Run() {

if !mh.isV3() {
Expand Down Expand Up @@ -930,105 +944,45 @@ const metricsdocsFragment = `
package main
import (
"bytes"
"fmt"
"sort"
"text/template"
"github.com/example/memcached-operator/monitoring"
)
// please run "make generate-metricsdocs" to run this tool and update metrics documentation
const (
title = "# Operator Metrics\n"
background = "This document aims to help users that are not familiar with metrics exposed by this operator.\n" +
"The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n"
KVSpecificMetrics = "## Operator Metrics List\n"
opening = title +
background +
KVSpecificMetrics
// footer
footerHeading = "## Developing new metrics\n"
footerContent = "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" +
"If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.\n"
footer = footerHeading + footerContent
)
// TODO: scaffolding these helpers with operator-lib: https://github.com/operator-framework/operator-lib.
// metricList contains the name, description, and type for each metric.
func main() {
metricList := metricDescriptionListToMetricList(monitoring.ListMetrics())
sort.Sort(metricList)
writeToStdOut(metricList)
}
metricDescriptions := monitoring.ListMetrics()
sort.Slice(metricDescriptions, func(i, j int) bool {
return metricDescriptions[i].Name < metricDescriptions[j].Name
})
tmpl, err := template.New("Operator metrics").Parse("# Operator Metrics\n" +
"This document aims to help users that are not familiar with metrics exposed by this operator.\n" +
"The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" +
"## Operator Metrics List" +
"{{range .}}\n" +
"### {{.Name}}\n" +
"{{.Help}} " +
"Type: {{.Type}}.\n" +
"{{end}}" +
"## Developing new metrics\n" +
"After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" +
"If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.")
// writeToStdOut receives a list of metrics and prints them to STDOUT.
func writeToStdOut(metricsList metricList) {
fmt.Print(opening)
metricsList.writeOut()
fmt.Print(footer)
}
// Metric is an exported struct that defines the metric
// name, description, and type as a new type named Metric.
type Metric struct {
name string
description string
metricType string
}
func metricDescriptionToMetric(md monitoring.MetricDescription) Metric {
return Metric{
name: md.Name,
description: md.Help,
metricType: md.Type,
if err != nil {
panic(err)
}
}
// writeOut receives a metric of type metric and prints
// the metric name, description, and type.
func (m Metric) writeOut() {
fmt.Println("###", m.name)
fmt.Println(m.description, "Type: "+m.metricType+".")
}
// metricList is an array that contain metrics from type metric,
// as a new type named metricList.
type metricList []Metric
// metricDescriptionListToMetricList collects the metrics exposed by the
// operator, and inserts them into the metricList array.
func metricDescriptionListToMetricList(mdl []monitoring.MetricDescription) metricList {
res := make([]Metric, len(mdl))
for i, md := range mdl {
res[i] = metricDescriptionToMetric(md)
// generate the template using the sorted list of metrics
var buf bytes.Buffer
if err := tmpl.Execute(&buf, metricDescriptions); err != nil {
panic(err)
}
return res
}
// 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 (m metricList) writeOut() {
for _, met := range m {
met.writeOut()
}
// print the generated metrics documentation
fmt.Println(buf.String())
}
`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,103 +17,43 @@ limitations under the License.
package main

import (
"bytes"
"fmt"
"sort"
"text/template"

"github.com/example/memcached-operator/monitoring"
)

// please run "make generate-metricsdocs" to run this tool and update metrics documentation
const (
title = "# Operator Metrics\n"
background = "This document aims to help users that are not familiar with metrics exposed by this operator.\n" +
"The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n"

KVSpecificMetrics = "## Operator Metrics List\n"

opening = title +
background +
KVSpecificMetrics

// footer
footerHeading = "## Developing new metrics\n"
footerContent = "After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" +
"If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.\n"

footer = footerHeading + footerContent
)

// TODO: scaffolding these helpers with operator-lib: https://github.com/operator-framework/operator-lib.

// metricList contains the name, description, and type for each metric.
func main() {
metricList := metricDescriptionListToMetricList(monitoring.ListMetrics())
sort.Sort(metricList)
writeToStdOut(metricList)
}

// writeToStdOut receives a list of metrics and prints them to STDOUT.
func writeToStdOut(metricsList metricList) {
fmt.Print(opening)
metricsList.writeOut()
fmt.Print(footer)
}

// Metric is an exported struct that defines the metric
// name, description, and type as a new type named Metric.
type Metric struct {
name string
description string
metricType string
}

func metricDescriptionToMetric(md monitoring.MetricDescription) Metric {
return Metric{
name: md.Name,
description: md.Help,
metricType: md.Type,
metricDescriptions := monitoring.ListMetrics()
sort.Slice(metricDescriptions, func(i, j int) bool {
return metricDescriptions[i].Name < metricDescriptions[j].Name
})

tmpl, err := template.New("Operator metrics").Parse("# Operator Metrics\n" +
"This document aims to help users that are not familiar with metrics exposed by this operator.\n" +
"The metrics documentation is auto-generated by the utility tool \"monitoring/metricsdocs\" and reflects all of the metrics that are exposed by the operator.\n\n" +
"## Operator Metrics List" +
"{{range .}}\n" +
"### {{.Name}}\n" +
"{{.Help}} " +
"Type: {{.Type}}.\n" +
"{{end}}" +
"## Developing new metrics\n" +
"After developing new metrics or changing old ones, please run \"make generate-metricsdocs\" to regenerate this document.\n\n" +
"If you feel that the new metric doesn't follow these rules, please change \"monitoring/metricsdocs\" according to your needs.")

if err != nil {
panic(err)
}
}

// writeOut receives a metric of type metric and prints
// the metric name, description, and type.
func (m Metric) writeOut() {
fmt.Println("###", m.name)
fmt.Println(m.description, "Type: "+m.metricType+".")
}

// metricList is an array that contain metrics from type metric,
// as a new type named metricList.
type metricList []Metric

// metricDescriptionListToMetricList collects the metrics exposed by the
// operator, and inserts them into the metricList array.
func metricDescriptionListToMetricList(mdl []monitoring.MetricDescription) metricList {
res := make([]Metric, len(mdl))
for i, md := range mdl {
res[i] = metricDescriptionToMetric(md)
// generate the template using the sorted list of metrics
var buf bytes.Buffer
if err := tmpl.Execute(&buf, metricDescriptions); err != nil {
panic(err)
}

return res
}

// 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 (m metricList) writeOut() {
for _, met := range m {
met.writeOut()
}
// print the generated metrics documentation
fmt.Println(buf.String())
}
Loading

0 comments on commit 034aef6

Please sign in to comment.