Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into hl_tag
Browse files Browse the repository at this point in the history
  • Loading branch information
Hardikl committed Nov 13, 2024
2 parents 67b323a + 59a050d commit 42d370a
Show file tree
Hide file tree
Showing 15 changed files with 460 additions and 99 deletions.
2 changes: 1 addition & 1 deletion cmd/collectors/rest/plugins/health/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (h *Health) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, *util

result = append(result, emsMat)
h.SLogger.Info(
"Collected",
"Health plugin",
slog.Int("numLicenseAlerts", licenseAlertCount),
slog.Int("numVolumeMoveAlerts", volumeMoveAlertCount),
slog.Int("numVolumeRansomwareAlerts", volumeRansomwareAlertCount),
Expand Down
31 changes: 22 additions & 9 deletions cmd/exporters/prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
histograms map[string]*histogram
normalizedLabels map[string][]string // cache of histogram normalized labels
instancesExported uint64
renderedBytes uint64
instanceKeysOk bool
buf bytes.Buffer // shared buffer for rendering
)
Expand Down Expand Up @@ -442,11 +443,13 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
prefixed := prefix + "_labels"
if tagged != nil && !tagged.Has(prefixed) {
tagged.Add(prefixed)
rendered = append(rendered,
[]byte("# HELP "+prefixed+" Pseudo-metric for "+data.Object+" labels"),
[]byte("# TYPE "+prefixed+" gauge"))
help := "# HELP " + prefixed + " Pseudo-metric for " + data.Object + " labels"
typeT := "# TYPE " + prefixed + " gauge"
rendered = append(rendered, []byte(help), []byte(typeT))
renderedBytes += uint64(len(help)) + uint64(len(typeT))
}
rendered = append(rendered, labelData)
renderedBytes += uint64(len(labelData))
}
}

Expand Down Expand Up @@ -503,12 +506,14 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
prefixedName := prefix + "_" + metric.GetName()
if tagged != nil && !tagged.Has(prefixedName) {
tagged.Add(prefixedName)
rendered = append(rendered,
[]byte("# HELP "+prefixedName+" Metric for "+data.Object),
[]byte("# TYPE "+prefixedName+" histogram"))
help := "# HELP " + prefixedName + " Metric for " + data.Object
typeT := "# TYPE " + prefixedName + " histogram"
rendered = append(rendered, []byte(help), []byte(typeT))
renderedBytes += uint64(len(help)) + uint64(len(typeT))
}

rendered = append(rendered, []byte(x))
renderedBytes += uint64(len(x))
// scalar metric
} else {
buf.Reset()
Expand Down Expand Up @@ -547,6 +552,7 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
copy(helpB, xbr)

rendered = append(rendered, helpB)
renderedBytes += uint64(len(helpB))

buf.Reset()
buf.WriteString("# TYPE ")
Expand All @@ -558,9 +564,11 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
copy(typeB, tbr)

rendered = append(rendered, typeB)
renderedBytes += uint64(len(typeB))
}

rendered = append(rendered, scalarMetric)
renderedBytes += uint64(len(scalarMetric))
}
}
}
Expand Down Expand Up @@ -592,9 +600,11 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
prefixedName := prefix + "_" + metric.GetName()
if tagged != nil && !tagged.Has(prefixedName) {
tagged.Add(prefix + "_" + metric.GetName())
rendered = append(rendered,
[]byte("# HELP "+prefixedName+" Metric for "+data.Object),
[]byte("# TYPE "+prefixedName+" histogram"))

help := "# HELP " + prefixedName + " Metric for " + data.Object
typeT := "# TYPE " + prefixedName + " histogram"
rendered = append(rendered, []byte(help), []byte(typeT))
renderedBytes += uint64(len(help)) + uint64(len(typeT))
}

normalizedNames, canNormalize := normalizedLabels[objectMetric]
Expand All @@ -616,15 +626,18 @@ func (p *Prometheus) render(data *matrix.Matrix) ([][]byte, exporter.Stats) {
x = prefix + "_" + metric.GetName() + "{" + joinedKeys + `,` + escape(p.replacer, "metric", bucketName) + "} " + value
}
rendered = append(rendered, []byte(x))
renderedBytes += uint64(len(x))
}
if canNormalize {
rendered = append(rendered, []byte(countMetric), []byte(sumMetric))
renderedBytes += uint64(len(countMetric)) + uint64(len(sumMetric))
}
}
}
stats := exporter.Stats{
InstancesExported: instancesExported,
MetricsExported: uint64(len(rendered)),
RenderedBytes: renderedBytes,
}

return rendered, stats
Expand Down
22 changes: 16 additions & 6 deletions cmd/harvest/harvest.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ func doManageCmd(cmd *cobra.Command, args []string) {
case "start":
startAllPollers(pollersFiltered, statusesByName)
}
printTable(pollersFiltered)
printTable(pollersFiltered, statusesByName)
}

func printTable(filteredPollers []string) {
func printTable(filteredPollers []string, statusesByName map[string][]*util.PollerStatus) {
table := tw.NewWriter(os.Stdout)
table.SetBorder(false)
table.SetAutoFormatHeaders(false)
Expand All @@ -186,7 +186,8 @@ func printTable(filteredPollers []string) {
}
table.SetColumnAlignment([]int{tw.ALIGN_LEFT, tw.ALIGN_LEFT, tw.ALIGN_RIGHT, tw.ALIGN_RIGHT, tw.ALIGN_RIGHT})
notRunning := &util.PollerStatus{Status: util.StatusNotRunning}
statusesByName := getPollersStatus()
disabled := &util.PollerStatus{Status: util.StatusDisabled}

for _, name := range filteredPollers {
var (
poller *conf.Poller
Expand All @@ -196,6 +197,7 @@ func printTable(filteredPollers []string) {
// should never happen, ignore since this was handled earlier
continue
}

if statuses, ok := statusesByName[name]; ok {
// print each status, annotate extra rows with a +
for i, status := range statuses {
Expand All @@ -207,7 +209,11 @@ func printTable(filteredPollers []string) {
}
} else {
// poller not running
printStatus(table, opts.longStatus, poller.Datacenter, name, notRunning)
if poller.IsDisabled {
printStatus(table, opts.longStatus, poller.Datacenter, name, disabled)
} else {
printStatus(table, opts.longStatus, poller.Datacenter, name, notRunning)
}
}
}
table.Render()
Expand All @@ -230,7 +236,11 @@ func startAllPollers(pollersFiltered []string, statusesByName map[string][]*util
startPoller(name, promPort, opts)
}
} else {
// poller not already running or just stopped
// poller not already running, just stopped, or disabled
poller, _ := conf.PollerNamed(name)
if poller == nil || poller.IsDisabled {
continue
}
promPort := getPollerPrometheusPort(name, opts)
startPoller(name, promPort, opts)
}
Expand All @@ -256,7 +266,7 @@ func getPollersStatus() map[string][]*util.PollerStatus {
fmt.Printf("Unable to GetPollerStatuses err: %+v\n", err)
return nil
}
// create map of status names
// create a map of status names
for _, status := range statuses {
statusesByName[status.Name] = append(statusesByName[status.Name], &status) // #nosec G601
}
Expand Down
27 changes: 15 additions & 12 deletions cmd/poller/collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,19 +529,21 @@ func (c *AbstractCollector) Start(wg *sync.WaitGroup) {

// Continue if metadata failed, since it might be specific to metadata
for _, data := range results {
if data.IsExportable() {
stats, err := e.Export(data)
if err != nil {
c.Logger.Error(
"export data",
slogx.Err(err),
slog.String("exporter", e.GetName()),
)
break
}
exporterStats.InstancesExported += stats.InstancesExported
exporterStats.MetricsExported += stats.MetricsExported
if !data.IsExportable() {
continue
}
stats, err := e.Export(data)
if err != nil {
c.Logger.Error(
"export data",
slogx.Err(err),
slog.String("exporter", e.GetName()),
)
break
}
exporterStats.InstancesExported += stats.InstancesExported
exporterStats.MetricsExported += stats.MetricsExported
exporterStats.RenderedBytes += stats.RenderedBytes
}
}

Expand Down Expand Up @@ -612,6 +614,7 @@ func (c *AbstractCollector) logMetadata(taskName string, stats exporter.Stats) {
int64Field("pluginInstances"),
timeToMilli("plugin_time"),
timeToMilli("poll_time"),
slog.Uint64("renderedBytes", stats.RenderedBytes),
int64Field("skips"),
int64Field("zBegin"),
)
Expand Down
1 change: 1 addition & 0 deletions cmd/poller/exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var status = [3]string{
type Stats struct {
InstancesExported uint64
MetricsExported uint64
RenderedBytes uint64
}

// AbstractExporter implements all methods of the Exporter interface, except Export()
Expand Down
69 changes: 68 additions & 1 deletion cmd/tools/doctor/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ func doDoctorCmd(cmd *cobra.Command, _ []string) {
pathI := conf.ConfigPath(config.Value.String())
confPath := confPaths.Value.String()
out := doDoctor(pathI)
fmt.Println(out)
if opts.ShouldPrintConfig {
fmt.Println(out)
}
checkAll(pathI, confPath)
}

Expand Down Expand Up @@ -233,6 +235,7 @@ func checkAll(aPath string, confPath string) {
anyFailed = !checkExporterTypes(cfg).isValid || anyFailed
anyFailed = !checkConfTemplates(confPaths).isValid || anyFailed
anyFailed = !checkCollectorName(cfg).isValid || anyFailed
anyFailed = !checkPollerPromPorts(cfg).isValid || anyFailed

if anyFailed {
os.Exit(1)
Expand Down Expand Up @@ -275,6 +278,7 @@ func checkCollectorName(config conf.HarvestConfig) validation {

// if no collector is configured in default and poller
if !isDefaultCollectorExist && !isPollerCollectorExist {
fmt.Printf("%s: No collectors are defined. Nothing will be collected.\n", color.Colorize("Error", color.Red))
valid.isValid = false
}

Expand Down Expand Up @@ -600,6 +604,69 @@ func printRedactedConfig(aPath string, contents []byte) (*yaml.Node, error) {
return root, nil
}

// checkPollerPromPorts checks that
// - pollers that define a prom_port do so uniquely.
// - when a prom_port is defined, but there are no Prometheus exporters
func checkPollerPromPorts(config conf.HarvestConfig) validation {
seen := make(map[int][]string)

for _, pName := range config.PollersOrdered {
poller := config.Pollers[pName]
if poller.PromPort == 0 {
continue
}
previous := seen[poller.PromPort]
previous = append(previous, pName)
seen[poller.PromPort] = previous
}

valid := validation{isValid: true}
for _, pollerNames := range seen {
if len(pollerNames) == 1 {
continue
}
valid.isValid = false
break
}

if !valid.isValid {
fmt.Printf("%s: Multiple pollers use the same prom_port.\n", color.Colorize("Error", color.Red))
fmt.Println(" Each poller's prom_port should be unique. Change the following pollers to use unique prom_ports:")

for port, pollerNames := range seen {
if len(pollerNames) == 1 {
continue
}
names := strings.Join(pollerNames, ", ")
fmt.Printf(" pollers [%s] specify the same prom_port: [%s]\n", color.Colorize(names, color.Yellow), color.Colorize(port, color.Red))
valid.invalid = append(valid.invalid, names)
}
fmt.Println()
}

// Check if there are any pollers that define a prom_port but there are no Prometheus exporters
if config.Exporters == nil {
fmt.Printf("%s: No Exporters section defined. At least one Prometheus exporter is needed for prom_port to export.\n", color.Colorize("Error", color.Red))
valid.invalid = append(valid.invalid, "No Prometheus exporters defined")
valid.isValid = false
} else {
hasPromExporter := false
for _, exporter := range config.Exporters {
if exporter.Type == "Prometheus" {
hasPromExporter = true
break
}
}
if !hasPromExporter {
fmt.Printf("%s: No Prometheus exporters defined. At least one Prometheus exporter is needed for prom_port to export.\n", color.Colorize("Error", color.Red))
valid.invalid = append(valid.invalid, "No Prometheus exporters defined")
valid.isValid = false
}
}

return valid
}

func sanitize(nodes []*yaml.Node) {
// Update this list when there are additional tokens to sanitize
sanitizeWords := []string{"username", "password", "grafana_api_token", "token",
Expand Down
12 changes: 12 additions & 0 deletions cmd/tools/doctor/doctor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,15 @@ func TestExportersExist(t *testing.T) {
t.Errorf(`got isValid=true, want isValid=false since there is no exporters section`)
}
}

func TestPollerPromPorts(t *testing.T) {
conf.TestLoadHarvestConfig("testdata/promPortNoPromExporters.yml")
valid := checkPollerPromPorts(conf.Config)
if valid.isValid {
t.Errorf(`got isValid=true, want isValid=false since there are non unique prom ports`)
}

if len(valid.invalid) != 2 {
t.Errorf(`got %d invalid, want 2`, len(valid.invalid))
}
}
19 changes: 19 additions & 0 deletions cmd/tools/doctor/testdata/promPortNoPromExporters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Exporters:
influx3:
exporter: InfluxDB
url: http://localhost:123809/api/v2/write?org=harvest&bucket=harvest&precision=s
token: my-token

Defaults:
datacenter: rtp
collectors:
- Rest

Pollers:
sar:
addr: 10.1.1.1
prom_port: 3000

abc:
addr: 10.1.1.1
prom_port: 3000
Loading

0 comments on commit 42d370a

Please sign in to comment.