Use metric configurations from Ganglia for some metrics

This commit is contained in:
Thomas Roehl 2022-02-23 13:38:59 +01:00
parent b605166119
commit 36c234315a
2 changed files with 67 additions and 141 deletions

View File

@ -24,6 +24,7 @@ type GangliaSinkConfig struct {
AddTagsAsDesc bool `json:"add_tags_as_desc,omitempty"` AddTagsAsDesc bool `json:"add_tags_as_desc,omitempty"`
ClusterName string `json:"cluster_name,omitempty"` ClusterName string `json:"cluster_name,omitempty"`
AddTypeToName bool `json:"add_type_to_name,omitempty"` AddTypeToName bool `json:"add_type_to_name,omitempty"`
AddUnits bool `json:"add_units,omitempty"`
} }
type GangliaSink struct { type GangliaSink struct {
@ -38,6 +39,7 @@ func (s *GangliaSink) Init(config json.RawMessage) error {
s.name = "GangliaSink" s.name = "GangliaSink"
s.config.AddTagsAsDesc = false s.config.AddTagsAsDesc = false
s.config.AddGangliaGroup = false s.config.AddGangliaGroup = false
s.config.AddUnits = false
if len(config) > 0 { if len(config) > 0 {
err := json.Unmarshal(config, &s.config) err := json.Unmarshal(config, &s.config)
if err != nil { if err != nil {
@ -70,91 +72,48 @@ func (s *GangliaSink) Init(config json.RawMessage) error {
func (s *GangliaSink) Write(point lp.CCMetric) error { func (s *GangliaSink) Write(point lp.CCMetric) error {
var err error = nil var err error = nil
var tagsstr []string //var tagsstr []string
var argstr []string var argstr []string
if s.config.AddGangliaGroup {
if point.HasTag("group") { // Get metric name
g, _ := point.GetTag("group") metricname := GangliaMetricRename(point.Name())
argstr = append(argstr, fmt.Sprintf("--group=%s", g))
} else if point.HasMeta("group") { // Get metric config (type, value, ... in suitable format)
g, _ := point.GetMeta("group") conf := GetCommonGangliaConfig(point)
argstr = append(argstr, fmt.Sprintf("--group=%s", g)) if len(conf.Type) == 0 {
} conf = GetGangliaConfig(point)
}
if len(conf.Type) == 0 {
return fmt.Errorf("metric %s has no 'value' field", metricname)
} }
for key, value := range point.Tags() { if s.config.AddGangliaGroup {
switch key { argstr = append(argstr, fmt.Sprintf("--group=%s", conf.Group))
case "unit":
argstr = append(argstr, fmt.Sprintf("--units=%s", value))
default:
tagsstr = append(tagsstr, fmt.Sprintf("%s=%s", key, value))
}
} }
if s.config.MetaAsTags { if s.config.AddUnits && len(conf.Unit) > 0 {
for key, value := range point.Meta() { argstr = append(argstr, fmt.Sprintf("--units=%s", conf.Unit))
switch key {
case "unit":
argstr = append(argstr, fmt.Sprintf("--units=%s", value))
default:
tagsstr = append(tagsstr, fmt.Sprintf("%s=%s", key, value))
}
}
} }
if len(s.config.ClusterName) > 0 { if len(s.config.ClusterName) > 0 {
argstr = append(argstr, fmt.Sprintf("--cluster=%s", s.config.ClusterName)) argstr = append(argstr, fmt.Sprintf("--cluster=%s", s.config.ClusterName))
} }
if s.config.AddTagsAsDesc && len(tagsstr) > 0 { // if s.config.AddTagsAsDesc && len(tagsstr) > 0 {
argstr = append(argstr, fmt.Sprintf("--desc=%q", strings.Join(tagsstr, ","))) // argstr = append(argstr, fmt.Sprintf("--desc=%q", strings.Join(tagsstr, ",")))
} // }
if len(s.gmetric_config) > 0 { if len(s.gmetric_config) > 0 {
argstr = append(argstr, fmt.Sprintf("--conf=%s", s.gmetric_config)) argstr = append(argstr, fmt.Sprintf("--conf=%s", s.gmetric_config))
} }
name := GangliaMetricRename(point)
if s.config.AddTypeToName { if s.config.AddTypeToName {
argstr = append(argstr, fmt.Sprintf("--name=%s", GangliaMetricName(point))) argstr = append(argstr, fmt.Sprintf("--name=%s", GangliaMetricName(point)))
} else { } else {
argstr = append(argstr, fmt.Sprintf("--name=%s", name)) argstr = append(argstr, fmt.Sprintf("--name=%s", metricname))
} }
slope := GangliaSlopeType(point) argstr = append(argstr, fmt.Sprintf("--slope=%s", conf.Slope))
slopeStr := "both" argstr = append(argstr, fmt.Sprintf("--value=%s", conf.Value))
if slope == 0 { argstr = append(argstr, fmt.Sprintf("--type=%s", conf.Type))
slopeStr = "zero" argstr = append(argstr, fmt.Sprintf("--tmax=%d", conf.Tmax))
}
argstr = append(argstr, fmt.Sprintf("--slope=%s", slopeStr))
for k, v := range point.Fields() { cclog.ComponentDebug(s.name, s.gmetric_path, strings.Join(argstr, " "))
if k == "value" {
switch value := v.(type) {
case float64:
argstr = append(argstr,
fmt.Sprintf("--value=%v", value), "--type=double")
case float32:
argstr = append(argstr,
fmt.Sprintf("--value=%v", value), "--type=float")
case int:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=int32")
case int32:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=int32")
case int64:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=int32")
case uint:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=uint32")
case uint32:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=uint32")
case uint64:
argstr = append(argstr,
fmt.Sprintf("--value=%d", value), "--type=uint32")
case string:
argstr = append(argstr,
fmt.Sprintf("--value=%q", value), "--type=string")
}
}
}
command := exec.Command(s.gmetric_path, argstr...) command := exec.Command(s.gmetric_path, argstr...)
command.Wait() command.Wait()
_, err = command.Output() _, err = command.Output()

View File

@ -82,21 +82,21 @@ const (
GMOND_CONFIG_FILE = `/etc/ganglia/gmond.conf` GMOND_CONFIG_FILE = `/etc/ganglia/gmond.conf`
) )
type LibgangliaSinkSpecialMetric struct { // type LibgangliaSinkSpecialMetric struct {
MetricName string `json:"metric_name,omitempty"` // MetricName string `json:"metric_name,omitempty"`
NewName string `json:"new_name,omitempty"` // NewName string `json:"new_name,omitempty"`
Slope string `json:"slope,omitempty"` // Slope string `json:"slope,omitempty"`
} // }
type LibgangliaSinkConfig struct { type LibgangliaSinkConfig struct {
defaultSinkConfig defaultSinkConfig
GangliaLib string `json:"libganglia_path,omitempty"` GangliaLib string `json:"libganglia_path,omitempty"`
GmondConfig string `json:"gmond_config,omitempty"` GmondConfig string `json:"gmond_config,omitempty"`
AddGangliaGroup bool `json:"add_ganglia_group,omitempty"` AddGangliaGroup bool `json:"add_ganglia_group,omitempty"`
AddTypeToName bool `json:"add_type_to_name,omitempty"` AddTypeToName bool `json:"add_type_to_name,omitempty"`
AddUnits bool `json:"add_units,omitempty"` AddUnits bool `json:"add_units,omitempty"`
ClusterName string `json:"cluster_name,omitempty"` ClusterName string `json:"cluster_name,omitempty"`
SpecialMetrics map[string]LibgangliaSinkSpecialMetric `json:"rename_metrics,omitempty"` // Map to rename metric name from key to value //SpecialMetrics map[string]LibgangliaSinkSpecialMetric `json:"rename_metrics,omitempty"` // Map to rename metric name from key to value
//AddTagsAsDesc bool `json:"add_tags_as_desc,omitempty"` //AddTagsAsDesc bool `json:"add_tags_as_desc,omitempty"`
} }
@ -184,81 +184,48 @@ func (s *LibgangliaSink) Write(point lp.CCMetric) error {
} }
// Get metric name // Get metric name
metricname := GangliaMetricRename(point) metricname := GangliaMetricRename(point.Name())
if s.config.AddTypeToName {
c_name = lookup(GangliaMetricName(point))
} else {
c_name = lookup(metricname)
}
// Get the value C string and lookup the type string in the cache conf := GetCommonGangliaConfig(point)
value, ok := point.GetField("value") if len(conf.Type) == 0 {
if !ok { conf = GetGangliaConfig(point)
}
if len(conf.Type) == 0 {
return fmt.Errorf("metric %s has no 'value' field", metricname) return fmt.Errorf("metric %s has no 'value' field", metricname)
} }
switch real := value.(type) {
case float64: if s.config.AddTypeToName {
c_value = C.CString(fmt.Sprintf("%f", real)) metricname = GangliaMetricName(point)
c_type = lookup("double")
case float32:
c_value = C.CString(fmt.Sprintf("%f", real))
c_type = lookup("float")
case int64:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("int32")
case int32:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("int32")
case int:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("int32")
case uint64:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("uint32")
case uint32:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("uint32")
case uint:
c_value = C.CString(fmt.Sprintf("%d", real))
c_type = lookup("uint32")
case string:
c_value = C.CString(real)
c_type = lookup("string")
default:
return fmt.Errorf("metric %s has invalid 'value' type for %s", point.Name(), s.name)
} }
c_value = C.CString(conf.Value)
c_type = lookup(conf.Type)
c_name = lookup(metricname)
// Add unit // Add unit
unit := ""
if s.config.AddUnits { if s.config.AddUnits {
if tagunit, tagok := point.GetTag("unit"); tagok { unit = conf.Unit
c_unit = lookup(tagunit)
} else if metaunit, metaok := point.GetMeta("unit"); metaok {
c_unit = lookup(metaunit)
} else {
c_unit = lookup("")
}
} else {
c_unit = lookup("")
} }
c_unit = lookup(unit)
// Determine the slope of the metric. Ganglia's own collector mostly use // Determine the slope of the metric. Ganglia's own collector mostly use
// 'both' but the mem and swap total uses 'zero'. // 'both' but the mem and swap total uses 'zero'.
slope := GangliaSlopeType(point)
slope_type := C.GANGLIA_SLOPE_BOTH slope_type := C.GANGLIA_SLOPE_BOTH
switch slope { switch conf.Slope {
case 0: case "zero":
slope_type = C.GANGLIA_SLOPE_ZERO slope_type = C.GANGLIA_SLOPE_ZERO
case "both":
slope_type = C.GANGLIA_SLOPE_BOTH
} }
// Create a new Ganglia metric // Create a new Ganglia metric
gmetric := C.Ganglia_metric_create(s.global_context) gmetric := C.Ganglia_metric_create(s.global_context)
// Set name, value, type and unit in the Ganglia metric // Set name, value, type and unit in the Ganglia metric
// Since we don't have this information from the collectors, // The default slope_type is both directions, so up and down. Some metrics want 'zero' slope, probably constant.
// we assume that the metric value can go up and down (slope), // The 'tmax' value is by default 300.
// and there is no maximum for 'dmax' and 'tmax'.
// Ganglia's collectors set 'tmax' but not 'dmax'
rval := C.int(0) rval := C.int(0)
rval = C.Ganglia_metric_set(gmetric, c_name, c_value, c_type, c_unit, C.uint(slope_type), 0, 0) rval = C.Ganglia_metric_set(gmetric, c_name, c_value, c_type, c_unit, C.uint(slope_type), C.uint(conf.Tmax), 0)
switch rval { switch rval {
case 1: case 1:
C.free(unsafe.Pointer(c_value)) C.free(unsafe.Pointer(c_value))
@ -268,10 +235,10 @@ func (s *LibgangliaSink) Write(point lp.CCMetric) error {
return errors.New("one of your parameters has an invalid character '\"'") return errors.New("one of your parameters has an invalid character '\"'")
case 3: case 3:
C.free(unsafe.Pointer(c_value)) C.free(unsafe.Pointer(c_value))
return fmt.Errorf("the type parameter \"%s\" is not a valid type", C.GoString(c_type)) return fmt.Errorf("the type parameter \"%s\" is not a valid type", conf.Type)
case 4: case 4:
C.free(unsafe.Pointer(c_value)) C.free(unsafe.Pointer(c_value))
return fmt.Errorf("the value parameter \"%s\" does not represent a number", C.GoString(c_value)) return fmt.Errorf("the value parameter \"%s\" does not represent a number", conf.Value)
default: default:
} }
@ -280,8 +247,8 @@ func (s *LibgangliaSink) Write(point lp.CCMetric) error {
C.Ganglia_metadata_add(gmetric, lookup("CLUSTER"), lookup(s.config.ClusterName)) C.Ganglia_metadata_add(gmetric, lookup("CLUSTER"), lookup(s.config.ClusterName))
} }
// Set the group metadata in the Ganglia metric if configured // Set the group metadata in the Ganglia metric if configured
if group, ok := point.GetMeta("group"); ok && s.config.AddGangliaGroup { if s.config.AddGangliaGroup {
c_group := lookup(group) c_group := lookup(conf.Group)
C.Ganglia_metadata_add(gmetric, lookup("GROUP"), c_group) C.Ganglia_metadata_add(gmetric, lookup("GROUP"), c_group)
} }