Fill HELP and TYPE for metrics.

Fixes #2.
This commit is contained in:
Stanislav Nikitin 2020-12-23 15:40:48 +05:00
parent c34babeaf8
commit 2e8fdb194c
Signed by: pztrn
GPG Key ID: 1E944A0F0568B550
2 changed files with 83 additions and 16 deletions

View File

@ -18,7 +18,7 @@ func (a *Application) parse(body string) map[string]models.Metric {
// Prometheus line contains metric name and metric parameters defined // Prometheus line contains metric name and metric parameters defined
// in "{}". // in "{}".
var ( var (
name, value string name string
params []string params []string
) )
@ -27,29 +27,61 @@ func (a *Application) parse(body string) map[string]models.Metric {
continue continue
} }
// Check that line isn't commented. We should skip comments for now. log.Println("Analyzing line:", line)
name = a.getMetricName(line)
metric, found := data[name]
if !found {
metric = models.NewMetric(name, "", "", nil)
}
// If line is commented - then we have something about metric's description
// or type. It should be handled in special way - these metric will became
// "pseudometric" which will be used as template for next iterations. For
// example if HELP line was parsed first, then TYPE line will be parsed and
// data will be added to already existing metric. If next line which should
// represent metric itself contains parameters (e.g. "{instance='host1'}")
// then next code block will COPY populated with HELP and TYPE pesudometric
// and put it's value as new metric with different name (metric/instance:host1
// in this example).
if strings.HasPrefix(line, "#") { if strings.HasPrefix(line, "#") {
switch strings.Split(line, " ")[1] {
case "HELP":
log.Println("Got HELP line")
metric.Description = a.getMetricDescription(line)
case "TYPE":
log.Println("Got TYPE line")
metric.Type = a.getMetricType(line)
}
data[name] = metric
// According to https://github.com/Showmax/prometheus-docs/blob/master/content/docs/instrumenting/exposition_formats.md
// HELP and TYPE lines should be printed before actual metric. Do not even
// report bugs regarding that!
continue continue
} }
log.Println("Analyzing line:", line) // Parametrized metrics should have own piece of love - we should
// add parameters to metric's name. This would also require metrics
// structure copying.
if strings.Contains(line, "{") {
newMetric := metric
// Check if we have parametrized metric. If no - push it to data map.
if !strings.Contains(line, "{") {
name = strings.Split(line, " ")[0]
value = strings.Split(line, " ")[1]
} else {
value = strings.Split(line, " ")[1]
name = strings.Split(line, "{")[0]
params = a.getParametersForPrometheusMetric(line) params = a.getParametersForPrometheusMetric(line)
for _, param := range params { for _, param := range params {
name += "/" + param newMetric.Name += "/" + param
}
} }
metric := models.NewMetric(name, "", "", params) metric = newMetric
metric.SetValue(value) data[metric.Name] = metric
}
metric.Value = a.getMetricValue(line)
log.Printf("Got metric: %+v\n", metric)
data[name] = metric data[name] = metric
} }
@ -59,6 +91,38 @@ func (a *Application) parse(body string) map[string]models.Metric {
return data return data
} }
// Gets metric description from passed line.
func (a *Application) getMetricDescription(line string) string {
return strings.Join(strings.Split(line, " ")[3:], " ")
}
// Gets metric name from passed line.
func (a *Application) getMetricName(line string) string {
var metricNameData string
if strings.HasPrefix(line, "#") {
metricNameData = strings.Split(line, " ")[2]
} else {
metricNameData = strings.Split(line, " ")[0]
}
return strings.Split(metricNameData, "{")[0]
}
// Gets metric type from passed line.
func (a *Application) getMetricType(line string) string {
return strings.Split(line, " ")[3]
}
// Gets metric value from passed line.
func (a *Application) getMetricValue(line string) string {
if strings.Contains(line, "}") {
return strings.Split(line, "} ")[1]
}
return strings.Split(line, " ")[1]
}
// Parses passed line and returns a slice of strings with parameters parsed. // Parses passed line and returns a slice of strings with parameters parsed.
func (a *Application) getParametersForPrometheusMetric(line string) []string { func (a *Application) getParametersForPrometheusMetric(line string) []string {
valuesString := strings.Split(strings.Split(line, "{")[1], "}")[0] valuesString := strings.Split(strings.Split(line, "{")[1], "}")[0]

View File

@ -74,8 +74,11 @@ func (s *Storage) Put(data map[string]models.Metric) {
defer s.dataMutex.Unlock() defer s.dataMutex.Unlock()
for k, v := range data { for k, v := range data {
// We should not put valueless metrics.
if v.Value != "" {
s.data[k] = v s.data[k] = v
} }
}
log.Println("Put", len(data), "items in", s.name) log.Println("Put", len(data), "items in", s.name)
} }