From 4f6c0b2dd31c92ffd6577ece3cb48b639000279b Mon Sep 17 00:00:00 2001 From: Chris Grindstaff Date: Wed, 22 May 2024 14:07:40 -0400 Subject: [PATCH] feat: log jitter during best-fit template loading doc: clarify that jitter applies to all collectors --- Makefile | 8 ++++---- cmd/collectors/rest/templating.go | 3 ++- cmd/collectors/storagegrid/storagegrid.go | 6 ++++-- cmd/collectors/zapi/collector/zapi.go | 5 +++-- cmd/poller/collector/helpers.go | 12 ++++++++++-- docs/configure-rest.md | 11 ++++++----- docs/configure-zapi.md | 13 +++++++------ 7 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 3968d9b20..68c36eca2 100644 --- a/Makefile +++ b/Makefile @@ -66,10 +66,10 @@ clean: ## Cleanup the project binary (bin) folders fi test: ## run tests - @echo "Running tests" - # The ldflags force the old Apple linker to suppress ld warning messages on MacOS - # See https://github.com/golang/go/issues/61229#issuecomment-1988965927 - go test -ldflags=-extldflags=-Wl,-ld_classic -race -shuffle=on ./... + @echo "Testing" + @# The ldflags force the old Apple linker to suppress ld warning messages on MacOS + @# See https://github.com/golang/go/issues/61229#issuecomment-1988965927 + @go test -ldflags=-extldflags=-Wl,-ld_classic -race -shuffle=on ./... fmt: ## format the go source files @echo "Formatting" diff --git a/cmd/collectors/rest/templating.go b/cmd/collectors/rest/templating.go index 7edc65109..00187fee7 100644 --- a/cmd/collectors/rest/templating.go +++ b/cmd/collectors/rest/templating.go @@ -13,7 +13,8 @@ import ( func (r *Rest) LoadTemplate() (string, error) { - template, path, err := r.ImportSubTemplate("", TemplateFn(r.Params, r.Object), r.Client.Cluster().Version) + jitter := r.Params.GetChildContentS("jitter") + template, path, err := r.ImportSubTemplate("", TemplateFn(r.Params, r.Object), jitter, r.Client.Cluster().Version) if err != nil { return "", err } diff --git a/cmd/collectors/storagegrid/storagegrid.go b/cmd/collectors/storagegrid/storagegrid.go index 14456a928..20df7cd9c 100644 --- a/cmd/collectors/storagegrid/storagegrid.go +++ b/cmd/collectors/storagegrid/storagegrid.go @@ -80,7 +80,7 @@ func (s *StorageGrid) Init(a *collector.AbstractCollector) error { return err } - s.Logger.Info().Msg("initialized") + s.Logger.Debug().Msg("initialized") return nil } @@ -472,7 +472,9 @@ func (s *StorageGrid) LoadTemplate() (string, error) { err error ) - template, path, err = s.ImportSubTemplate("", rest.TemplateFn(s.Params, s.Object), s.client.Cluster.Version) + jitter := s.Params.GetChildContentS("jitter") + + template, path, err = s.ImportSubTemplate("", rest.TemplateFn(s.Params, s.Object), jitter, s.client.Cluster.Version) if err != nil { return "", err } diff --git a/cmd/collectors/zapi/collector/zapi.go b/cmd/collectors/zapi/collector/zapi.go index 326371717..8da576e48 100644 --- a/cmd/collectors/zapi/collector/zapi.go +++ b/cmd/collectors/zapi/collector/zapi.go @@ -87,11 +87,12 @@ func (z *Zapi) Init(a *collector.AbstractCollector) error { } func (z *Zapi) InitVars() error { + jitter := z.Params.GetChildContentS("jitter") // It's used for unit tests only if z.Options.IsTest { z.Client = client.NewTestClient() templateName := z.Params.GetChildS("objects").GetChildContentS(z.Object) - template, path, err := z.ImportSubTemplate("cdot", templateName, [3]int{9, 8, 0}) + template, path, err := z.ImportSubTemplate("cdot", templateName, jitter, [3]int{9, 8, 0}) if err != nil { return err } @@ -123,7 +124,7 @@ func (z *Zapi) InitVars() error { z.HostModel = model templateName := z.Params.GetChildS("objects").GetChildContentS(z.Object) - template, path, err := z.ImportSubTemplate(model, templateName, z.Client.Version()) + template, path, err := z.ImportSubTemplate(model, templateName, jitter, z.Client.Version()) if err != nil { return err } diff --git a/cmd/poller/collector/helpers.go b/cmd/poller/collector/helpers.go index d2448e9d4..179608e8f 100644 --- a/cmd/poller/collector/helpers.go +++ b/cmd/poller/collector/helpers.go @@ -52,7 +52,7 @@ var versionRegex = regexp.MustCompile(`\d+\.\d+\.\d+`) // are sorted, and we try to return the subtemplate that most closely matches the ONTAP version. // Model is cdot or 7mode, filename is the name of the subtemplate, and ver is the // ONTAP version triple (generation, major, minor) -func (c *AbstractCollector) ImportSubTemplate(model, filename string, ver [3]int) (*node.Node, string, error) { +func (c *AbstractCollector) ImportSubTemplate(model, filename, jitter string, ver [3]int) (*node.Node, string, error) { var ( selectedVersion, templatePath string @@ -85,7 +85,15 @@ nextFile: } templatePath = filepath.Join(selectedVersion, f) - c.Logger.Info().Str("path", templatePath).Str("v", verWithDots).Msg("best-fit template") + if jitter == "" { + jitter = "none" + } + + c.Logger.Info(). + Str("path", templatePath). + Str("v", verWithDots). + Str("jitter", jitter). + Msg("best-fit template") if finalTemplate == nil { finalTemplate, err = tree.ImportYaml(templatePath) if err == nil { diff --git a/docs/configure-rest.md b/docs/configure-rest.md index d9823cb86..223619c64 100644 --- a/docs/configure-rest.md +++ b/docs/configure-rest.md @@ -73,11 +73,12 @@ explained in the next section). Additionally, this file contains the parameters that are applied as defaults to all objects. As mentioned before, any of these parameters can be defined in the Harvest or object configuration files as well. -| parameter | type | description | default | -|------------------|----------------------|-------------------------------------------------------------------------|-----------| -| `client_timeout` | duration (Go-syntax) | how long to wait for server responses | 30s | -| `schedule` | list, **required** | how frequently to retrieve metrics from ONTAP | | -| - `data` | duration (Go-syntax) | how frequently this collector/object should retrieve metrics from ONTAP | 3 minutes | +| parameter | type | description | default | +|------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------| +| `client_timeout` | duration (Go-syntax) | how long to wait for server responses | 30s | +| `jitter` | duration (Go-syntax), optional | Each Harvest collector runs independently, which means that at startup, each collector may send its REST queries at nearly the same time. To spread out the collector startup times over a broader period, you can use `jitter` to randomly distribute collector startup across a specified duration. For example, a `jitter` of `1m` starts each collector after a random delay between 0 and 60 seconds. For more details, refer to [this discussion](https://github.com/NetApp/harvest/discussions/2856). | | +| `schedule` | list, **required** | how frequently to retrieve metrics from ONTAP | | +| - `data` | duration (Go-syntax) | how frequently this collector/object should retrieve metrics from ONTAP | 3 minutes | The template should define objects in the `objects` section. Example: diff --git a/docs/configure-zapi.md b/docs/configure-zapi.md index 175541cd2..6dc5a7883 100644 --- a/docs/configure-zapi.md +++ b/docs/configure-zapi.md @@ -65,12 +65,13 @@ The full set of parameters are described [below](#collector-configuration-file). The parameters are similar to those of the [ZapiPerf collector](#zapiperf-collector). Parameters different from ZapiPerf: -| parameter | type | description | default | -|-------------------------|----------------|--------------------------------------------------------------------------------------------------------------|---------| -| `schedule` | required | same as for ZapiPerf, but only two elements: `instance` and `data` (collector does not run a `counter` poll) | | -| `no_max_records` | bool, optional | don't add `max-records` to the ZAPI request | | -| `collect_only_labels` | bool, optional | don't look for numeric metrics, only submit labels (suppresses the `ErrNoMetrics` error) | | -| `only_cluster_instance` | bool, optional | don't look for instance keys and assume only instance is the cluster itself | | +| parameter | type | description | default | +|-------------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| +| `jitter` | duration (Go-syntax), optional | Each Harvest collector runs independently, which means that at startup, each collector may send its ZAPI queries at nearly the same time. To spread out the collector startup times over a broader period, you can use `jitter` to randomly distribute collector startup across a specified duration. For example, a `jitter` of `1m` starts each collector after a random delay between 0 and 60 seconds. For more details, refer to [this discussion](https://github.com/NetApp/harvest/discussions/2856). | | +| `schedule` | required | same as for ZapiPerf, but only two elements: `instance` and `data` (collector does not run a `counter` poll) | | +| `no_max_records` | bool, optional | don't add `max-records` to the ZAPI request | | +| `collect_only_labels` | bool, optional | don't look for numeric metrics, only submit labels (suppresses the `ErrNoMetrics` error) | | +| `only_cluster_instance` | bool, optional | don't look for instance keys and assume only instance is the cluster itself | | #### Object configuration file