Skip to content

Commit

Permalink
Issue #124.
Browse files Browse the repository at this point in the history
An attempt to clean up the code
that converts Artifactory strings
to numbers accepted in Prometheus.
  • Loading branch information
KacperPerschke committed Feb 24, 2024
1 parent 8dfb2ca commit 2221844
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 93 deletions.
108 changes: 108 additions & 0 deletions collector/converter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package collector

import (
"fmt"
"regexp"
"strings"
)

// convArtiBoolToProm is a very interesting appendix.
// Something needs it, but what and why?
// It would be quite nice if it was written here why such a thing is needed.
func convArtiBoolToProm(b bool) float64 {
if b {
return 1
}
return 0
}

const (
pattOneNumber = `^(?P<number>[[:digit:]]{1,3}(?:,[[:digit:]]{3})*)(?:\.[[:digit:]]{1,2})? ?(?P<multiplier>%|bytes|[KMGT]B)?$`
)

var (
reOneNumber = regexp.MustCompile(pattOneNumber)
)

func (e *Exporter) convNumArtiToProm(artiNum string) (float64, error) {
e.logger.Debug(
"Attempting to convert a string from artifactory representing a number.",
"artifactory.number", artiNum,
)

if !reOneNumber.MatchString(artiNum) {
e.logger.Debug(
"The arti number did not match known templates.",
"artifactory.number", artiNum,
)
err := fmt.Errorf(
`The string '%s' does not match pattern '%s'.`,
artiNum,
pattOneNumber,
)
return 0, err
}

groups := extractNamedGroups(artiNum, reOneNumber)

// The following `strings.replace` is for those cases that contain a comma
// thousands separator. In other cases, unnecessary, but cheaper than if.
// Sorry.
f, err := e.convNumber(
strings.Replace(groups["number"], `,`, ``, -1),
)
if err != nil {
return 0, err
}

mAsString, mIsPresent := groups["multiplier"]
if !mIsPresent {
return f, nil
}
m, err := e.convMultiplier(mAsString)
if err != nil {
return 0, err
}

return f * m, nil
}

const (
pattTBytesPercent = `^(?P<tbytes>[[:digit:]]+(?:\.[[:digit:]]{1,2})?) TB \((?P<percent>[[:digit:]]{1,2}(?:\.[[:digit:]]{1,2})?)%\)$`
)

var (
reTBytesPercent = regexp.MustCompile(pattTBytesPercent)
)

func (e *Exporter) convTwoNumsArtiToProm(artiSize string) (float64, float64, error) {
e.logger.Debug(
"Attempting to convert a string from artifactory representing a number.",
"artifactory.number", artiSize,
)

if !reTBytesPercent.MatchString(artiSize) {
e.logger.Debug(
"The arti number did not match known templates.",
"artifactory.number", artiSize,
)
err := fmt.Errorf(
`The string '%s' does not match '%s' pattern.`,
artiSize,
pattTBytesPercent,
)
return 0, 0, err
}
groups := extractNamedGroups(artiSize, reTBytesPercent)
b, err := e.convNumber(groups["tbytes"])
if err != nil {
return 0, 0, err
}
mulTB, _ := e.convMultiplier(`TB`)
p, err := e.convNumber(groups["percent"])
if err != nil {
return 0, 0, err
}
mulPercent, _ := e.convMultiplier(`%`)
return b * mulTB, p * mulPercent, nil
}
54 changes: 54 additions & 0 deletions collector/converter_internals.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package collector

import (
"fmt"
"math"
"regexp"
"strconv"
)

var mulConvDriver = map[string]float64{
`%`: 0.01,
`bytes`: 1,
`KB`: math.Exp2(10),
`MB`: math.Exp2(20),
`GB`: math.Exp2(30),
`TB`: math.Exp2(40),
}

func (e *Exporter) convMultiplier(m string) (float64, error) {
mul, present := mulConvDriver[m]
if present {
return mul, nil
}
e.logger.Error(
"The string was not recognized as a known multiplier.",
"artifactory.number.multiplier", m,
)
return 0, fmt.Errorf(`Could not recognise '%s; as multiplier`, m)
}

func (e *Exporter) convNumber(n string) (float64, error) {
f, err := strconv.ParseFloat(n, 64)
if err != nil {
e.logger.Error(
"String not convertible to float64",
"string", n,
)
return 0, err
}
return f, nil
}

type reCaptureGroups map[string]string

func extractNamedGroups(artiNum string, re *regexp.Regexp) reCaptureGroups {
match := re.FindStringSubmatch(artiNum)
groupsFound := make(reCaptureGroups)
for i, name := range re.SubexpNames() {
if i != 0 && name != "" {
groupsFound[name] = match[i]
}
}
return groupsFound
}
2 changes: 1 addition & 1 deletion collector/replication.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (e *Exporter) exportReplications(ch chan<- prometheus.Metric) error {
for metricName, metric := range replicationMetrics {
switch metricName {
case "enabled":
enabled := b2f(replication.Enabled)
enabled := convArtiBoolToProm(replication.Enabled)
repo := replication.RepoKey
rType := strings.ToLower(replication.ReplicationType)
rURL := strings.ToLower(replication.URL)
Expand Down
21 changes: 16 additions & 5 deletions collector/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (e *Exporter) exportCount(metricName string, metric *prometheus.Desc, count
e.jsonParseFailures.Inc()
return
}
value, err := e.removeCommas(count)
value, err := e.convNumArtiToProm(count)
if err != nil {
e.jsonParseFailures.Inc()
e.logger.Error(
Expand All @@ -38,7 +38,7 @@ func (e *Exporter) exportSize(metricName string, metric *prometheus.Desc, size s
e.jsonParseFailures.Inc()
return
}
value, err := e.bytesConverter(size)
value, err := e.convNumArtiToProm(size)
if err != nil {
e.jsonParseFailures.Inc()
e.logger.Error(
Expand All @@ -61,7 +61,11 @@ func (e *Exporter) exportFilestore(metricName string, metric *prometheus.Desc, s
e.jsonParseFailures.Inc()
return
}
value, err := e.bytesConverter(size)
value, percent, err := e.convTwoNumsArtiToProm(size)
/*
* What should you use the percentage for?
* Maybe Issue #126?
*/
if err != nil {
e.jsonParseFailures.Inc()
e.logger.Warn(
Expand All @@ -75,6 +79,7 @@ func (e *Exporter) exportFilestore(metricName string, metric *prometheus.Desc, s
logDbgMsgRegMetric,
"metric", metricName,
"value", value,
"percent", percent,
)
ch <- prometheus.MustNewConstMetric(metric, prometheus.GaugeValue, value, fileStoreType, fileStoreDir, nodeId)
}
Expand Down Expand Up @@ -112,7 +117,7 @@ func (e *Exporter) extractRepo(storageInfo artifactory.StorageInfo) ([]repoSumma
rs.FilesCount = float64(repo.FilesCount)
rs.ItemsCount = float64(repo.ItemsCount)
rs.PackageType = strings.ToLower(repo.PackageType)
rs.UsedSpace, err = e.bytesConverter(repo.UsedSpace)
rs.UsedSpace, err = e.convNumArtiToProm(repo.UsedSpace)
if err != nil {
e.logger.Warn(
"There was an issue parsing repo UsedSpace",
Expand All @@ -125,7 +130,13 @@ func (e *Exporter) extractRepo(storageInfo artifactory.StorageInfo) ([]repoSumma
if repo.Percentage == "N/A" {
rs.Percentage = 0
} else {
rs.Percentage, err = e.removeCommas(repo.Percentage)
/* WARNING!
* Previous e.removeCommas have been returning float from range [0.0, 100.0]
* Actual convNumArtiToProm returns float from range [0.0, 1.0]
* The application's behavior in this matter requires
* close observation in the near future.
*/
rs.Percentage, err = e.convNumArtiToProm(repo.Percentage)
if err != nil {
e.logger.Warn(
"There was an issue parsing repo Percentage",
Expand Down
2 changes: 1 addition & 1 deletion collector/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (e *Exporter) exportSystem(license artifactory.LicenseInfo, ch chan<- prome
for metricName, metric := range systemMetrics {
switch metricName {
case "healthy":
ch <- prometheus.MustNewConstMetric(metric, prometheus.GaugeValue, b2f(health.Healthy), health.NodeId)
ch <- prometheus.MustNewConstMetric(metric, prometheus.GaugeValue, convArtiBoolToProm(health.Healthy), health.NodeId)
case "version":
ch <- prometheus.MustNewConstMetric(metric, prometheus.GaugeValue, 1, buildInfo.Version, buildInfo.Revision, buildInfo.NodeId)
case "license":
Expand Down
86 changes: 0 additions & 86 deletions collector/utils.go

This file was deleted.

0 comments on commit 2221844

Please sign in to comment.