mirror of
				https://github.com/ClusterCockpit/cc-metric-collector.git
				synced 2025-11-04 02:35:07 +01:00 
			
		
		
		
	Units with cc-units (#64)
* Add option to normalize units with cc-unit * Add unit conversion to router * Add option to change unit prefix in the router * Add to MetricRouter README * Add order of operations in router to README * Use second add_tags/del_tags only if metric gets renamed
This commit is contained in:
		@@ -52,6 +52,11 @@ The CCMetric router sits in between the collectors and the sinks and can be used
 | 
			
		||||
    ],
 | 
			
		||||
    "rename_metrics" : {
 | 
			
		||||
        "metric_12345" : "mymetric"
 | 
			
		||||
    },
 | 
			
		||||
    "normalize_units" : true,
 | 
			
		||||
    "change_unit_prefix" {
 | 
			
		||||
      "mem_used" : "G",
 | 
			
		||||
      "mem_total" : "G"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
@@ -192,6 +197,14 @@ This option takes a list of evaluable conditions and performs them one after the
 | 
			
		||||
```
 | 
			
		||||
The first line is comparable with the example in `drop_metrics`, it drops all metrics starting with `drop_metric_` and ending with a number. The second line drops all metrics of the first hardware thread (**not** recommended)
 | 
			
		||||
 | 
			
		||||
# Manipulating the metric units
 | 
			
		||||
 | 
			
		||||
## The `normalize_units` option
 | 
			
		||||
The cc-metric-collector tries to read the data from the system as it is reported. If available, it tries to read the metric unit from the system as well (e.g. from `/proc/meminfo`). The problem is that, depending on the source, the metric units are named differently. Just think about `byte`, `Byte`, `B`, `bytes`, ...
 | 
			
		||||
The [cc-units](https://github.com/ClusterCockpit/cc-units) package provides us a normalization option to use the same metric unit name for all metrics. It this option is set to true, all `unit` meta tags are normalized.
 | 
			
		||||
 | 
			
		||||
## The `change_unit_prefix` section
 | 
			
		||||
It is often the case that metrics are reported by the system using a rather outdated unit prefix (like `/proc/meminfo` still uses kByte despite current memory sizes are in the GByte range). If you want to change the prefix of a unit, you can do that with the help of [cc-units](https://github.com/ClusterCockpit/cc-units). The setting works on the metric name and requires the new prefix for the metric. The cc-units package determines the scaling factor.
 | 
			
		||||
 | 
			
		||||
# Aggregate metric values of the current interval with the `interval_aggregates` option
 | 
			
		||||
 | 
			
		||||
@@ -239,3 +252,22 @@ Use cases for `interval_aggregates`:
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
# Order of operations
 | 
			
		||||
 | 
			
		||||
The router performs the above mentioned options in a specific order. In order to get the logic you want for a specific metric, it is crucial to know the processing order:
 | 
			
		||||
 | 
			
		||||
- Add the `hostname` tag (c)
 | 
			
		||||
- Manipulate the timestamp to the interval timestamp (c,r)
 | 
			
		||||
- Drop metrics based on `drop_metrics` and `drop_metrics_if` (c,r)
 | 
			
		||||
- Add tags based on `add_tags` (c,r)
 | 
			
		||||
- Delete tags based on `del_tags` (c,r)
 | 
			
		||||
- Rename metric based on `rename_metric` (c,r)
 | 
			
		||||
  - Add tags based on `add_tags` to still work if the configuration uses the new name (c,r) 
 | 
			
		||||
  - Delete tags based on `del_tags` to still work if the configuration uses the new name (c,r)
 | 
			
		||||
- Normalize units when `normalize_units` is set (c,r)
 | 
			
		||||
- Convert unit prefix based on `change_unit_prefix` (c,r)
 | 
			
		||||
 | 
			
		||||
Legend:
 | 
			
		||||
- 'c' if metric is coming from a collector
 | 
			
		||||
- 'r' if metric is coming from a receiver
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric"
 | 
			
		||||
	agg "github.com/ClusterCockpit/cc-metric-collector/internal/metricAggregator"
 | 
			
		||||
	mct "github.com/ClusterCockpit/cc-metric-collector/internal/multiChanTicker"
 | 
			
		||||
	units "github.com/ClusterCockpit/cc-units"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ROUTER_MAX_FORWARD = 50
 | 
			
		||||
@@ -35,6 +36,8 @@ type metricRouterConfig struct {
 | 
			
		||||
	IntervalStamp     bool                                 `json:"interval_timestamp"`  // Update timestamp periodically by ticker each interval?
 | 
			
		||||
	NumCacheIntervals int                                  `json:"num_cache_intervals"` // Number of intervals of cached metrics for evaluation
 | 
			
		||||
	MaxForward        int                                  `json:"max_forward"`         // Number of maximal forwarded metrics at one select
 | 
			
		||||
	NormalizeUnits    bool                                 `json:"normalize_units"`     // Check unit meta flag and normalize it using cc-units
 | 
			
		||||
	ChangeUnitPrefix  map[string]string                    `json:"change_unit_prefix"`  // Add prefix that should be applied to the metrics
 | 
			
		||||
	dropMetrics       map[string]bool                      // Internal map for O(1) lookup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -207,6 +210,38 @@ func (r *metricRouter) dropMetric(point lp.CCMetric) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *metricRouter) prepareUnit(point lp.CCMetric) bool {
 | 
			
		||||
	if r.config.NormalizeUnits {
 | 
			
		||||
		if in_unit, ok := point.GetMeta("unit"); ok {
 | 
			
		||||
			u := units.NewUnit(in_unit)
 | 
			
		||||
			if u.Valid() {
 | 
			
		||||
				point.AddMeta("unit", u.Short())
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if newP, ok := r.config.ChangeUnitPrefix[point.Name()]; ok {
 | 
			
		||||
 | 
			
		||||
		newPrefix := units.NewPrefix(newP)
 | 
			
		||||
 | 
			
		||||
		if in_unit, ok := point.GetMeta("unit"); ok && newPrefix != units.InvalidPrefix {
 | 
			
		||||
			u := units.NewUnit(in_unit)
 | 
			
		||||
			if u.Valid() {
 | 
			
		||||
				cclog.ComponentDebug("MetricRouter", "Change prefix to", newP, "for metric", point.Name())
 | 
			
		||||
				conv, out_unit := units.GetUnitPrefixFactor(u, newPrefix)
 | 
			
		||||
				if conv != nil && out_unit.Valid() {
 | 
			
		||||
					if val, ok := point.GetField("value"); ok {
 | 
			
		||||
						point.AddField("value", conv(val))
 | 
			
		||||
						point.AddMeta("unit", out_unit.Short())
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start starts the metric router
 | 
			
		||||
func (r *metricRouter) Start() {
 | 
			
		||||
	// start timer if configured
 | 
			
		||||
@@ -232,9 +267,11 @@ func (r *metricRouter) Start() {
 | 
			
		||||
		if new, ok := r.config.RenameMetrics[name]; ok {
 | 
			
		||||
			point.SetName(new)
 | 
			
		||||
			point.AddMeta("oldname", name)
 | 
			
		||||
		}
 | 
			
		||||
			r.DoAddTags(point)
 | 
			
		||||
			r.DoDelTags(point)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r.prepareUnit(point)
 | 
			
		||||
 | 
			
		||||
		for _, o := range r.outputs {
 | 
			
		||||
			o <- point
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user