mirror of
				https://github.com/ClusterCockpit/cc-metric-collector.git
				synced 2025-10-30 16:45:07 +01:00 
			
		
		
		
	Change CCMetric's internal data structure (#22)
* package ccmetric rewrite * Create deep copy in New() to avoid access conflicts * Renamed TagMap() -> Tags(), MetaMap() -> Meta Co-authored-by: Holger Obermaier <40787752+ho-ob@users.noreply.github.com>
This commit is contained in:
		| @@ -14,62 +14,73 @@ import ( | ||||
| // | ||||
| // See: https://docs.influxdata.com/influxdb/latest/reference/syntax/line-protocol/ | ||||
| type ccMetric struct { | ||||
| 	name   string      // Measurement name | ||||
| 	tags   []*lp.Tag   // ordered list of of tags | ||||
| 	fields []*lp.Field // unordered list of of fields | ||||
| 	tm     time.Time   // timestamp | ||||
| 	meta   []*lp.Tag   // odered list of meta data tags | ||||
| 	name   string            // Measurement name | ||||
| 	meta   map[string]string // map of meta data tags | ||||
| 	tags   map[string]string // map of of tags | ||||
| 	fields []*lp.Field       // unordered list of of fields | ||||
| 	tm     time.Time         // timestamp | ||||
| } | ||||
|  | ||||
| // ccmetric access functions | ||||
| type CCMetric interface { | ||||
| 	lp.MutableMetric                         // SetTime, AddTag, AddField | ||||
| 	AddMeta(key, value string)               // Add a meta data tag | ||||
| 	MetaList() []*lp.Tag                     // Returns the meta data list | ||||
| 	RemoveTag(key string)                    // Remove a tag addressed by its key | ||||
| 	GetTag(key string) (string, bool)        // Get a tag addressed by its key | ||||
| 	GetMeta(key string) (string, bool)       // Get a meta data tab addressed by its key | ||||
| 	lp.Metric // Time(), Name(), TagList(), FieldList() | ||||
|  | ||||
| 	SetTime(t time.Time) | ||||
|  | ||||
| 	Meta() map[string]string           // Map of meta data tags | ||||
| 	MetaList() []*lp.Tag               // Ordered list of meta data | ||||
| 	AddMeta(key, value string)         // Add a meta data tag | ||||
| 	GetMeta(key string) (string, bool) // Get a meta data tab addressed by its key | ||||
|  | ||||
| 	Tags() map[string]string          // Map of tags | ||||
| 	AddTag(key, value string)         // Add a tag | ||||
| 	GetTag(key string) (string, bool) // Get a tag by its key | ||||
| 	RemoveTag(key string)             // Remove a tag by its key | ||||
|  | ||||
| 	GetField(key string) (interface{}, bool) // Get a field addressed by its key | ||||
| 	HasField(key string) bool                // Check if a field key is present | ||||
| 	RemoveField(key string)                  // Remove a field addressed by its key | ||||
| } | ||||
|  | ||||
| // Meta returns the list of meta data tags as key-value mapping | ||||
| // Meta returns the meta data tags as key-value mapping | ||||
| func (m *ccMetric) Meta() map[string]string { | ||||
| 	meta := make(map[string]string, len(m.meta)) | ||||
| 	for _, m := range m.meta { | ||||
| 		meta[m.Key] = m.Value | ||||
| 	} | ||||
| 	return meta | ||||
| 	return m.meta | ||||
| } | ||||
|  | ||||
| // MetaList returns the list of meta data tags | ||||
| // MetaList returns the the list of meta data tags as sorted list of key value tags | ||||
| func (m *ccMetric) MetaList() []*lp.Tag { | ||||
| 	return m.meta | ||||
|  | ||||
| 	ml := make([]*lp.Tag, 0, len(m.meta)) | ||||
| 	for key, value := range m.meta { | ||||
| 		ml = append(ml, &lp.Tag{Key: key, Value: value}) | ||||
| 	} | ||||
| 	sort.Slice(ml, func(i, j int) bool { return ml[i].Key < ml[j].Key }) | ||||
| 	return ml | ||||
| } | ||||
|  | ||||
| // String implements the stringer interface for data type ccMetric | ||||
| func (m *ccMetric) String() string { | ||||
| 	return fmt.Sprintf("%s %v %v %v %d", m.name, m.Tags(), m.Meta(), m.Fields(), m.tm.UnixNano()) | ||||
| 	return fmt.Sprintf("%s %v %v %v %d", m.name, m.tags, m.meta, m.Fields(), m.tm.UnixNano()) | ||||
| } | ||||
|  | ||||
| // Name returns the metric name | ||||
| // Name returns the measurement name | ||||
| func (m *ccMetric) Name() string { | ||||
| 	return m.name | ||||
| } | ||||
|  | ||||
| // Tags returns the the list of tags as key-value-mapping | ||||
| func (m *ccMetric) Tags() map[string]string { | ||||
| 	tags := make(map[string]string, len(m.tags)) | ||||
| 	for _, tag := range m.tags { | ||||
| 		tags[tag.Key] = tag.Value | ||||
| 	} | ||||
| 	return tags | ||||
| 	return m.tags | ||||
| } | ||||
|  | ||||
| // TagList returns the list of tags | ||||
| // TagList returns the the list of tags as sorted list of key value tags | ||||
| func (m *ccMetric) TagList() []*lp.Tag { | ||||
| 	return m.tags | ||||
| 	tl := make([]*lp.Tag, 0, len(m.tags)) | ||||
| 	for key, value := range m.tags { | ||||
| 		tl = append(tl, &lp.Tag{Key: key, Value: value}) | ||||
| 	} | ||||
| 	sort.Slice(tl, func(i, j int) bool { return tl[i].Key < tl[j].Key }) | ||||
| 	return tl | ||||
| } | ||||
|  | ||||
| // Fields returns the list of fields as key-value-mapping | ||||
| @@ -99,112 +110,50 @@ func (m *ccMetric) SetTime(t time.Time) { | ||||
|  | ||||
| // HasTag checks if a tag with key equal to <key> is present in the list of tags | ||||
| func (m *ccMetric) HasTag(key string) bool { | ||||
| 	for _, tag := range m.tags { | ||||
| 		if tag.Key == key { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| 	_, ok := m.tags[key] | ||||
| 	return ok | ||||
| } | ||||
|  | ||||
| // GetTag returns the tag with tag's key equal to <key> | ||||
| func (m *ccMetric) GetTag(key string) (string, bool) { | ||||
| 	for _, tag := range m.tags { | ||||
| 		if tag.Key == key { | ||||
| 			return tag.Value, true | ||||
| 		} | ||||
| 	} | ||||
| 	return "", false | ||||
| 	value, ok := m.tags[key] | ||||
| 	return value, ok | ||||
| } | ||||
|  | ||||
| // RemoveTag removes the tag with tag's key equal to <key> | ||||
| // and keeps the tag list ordered by the keys | ||||
| func (m *ccMetric) RemoveTag(key string) { | ||||
| 	for i, tag := range m.tags { | ||||
| 		if tag.Key == key { | ||||
| 			copy(m.tags[i:], m.tags[i+1:]) | ||||
| 			m.tags[len(m.tags)-1] = nil | ||||
| 			m.tags = m.tags[:len(m.tags)-1] | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	delete(m.tags, key) | ||||
| } | ||||
|  | ||||
| // AddTag adds a tag (consisting of key and value) | ||||
| // and keeps the tag list ordered by the keys | ||||
| func (m *ccMetric) AddTag(key, value string) { | ||||
| 	for i, tag := range m.tags { | ||||
| 		if key > tag.Key { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if key == tag.Key { | ||||
| 			tag.Value = value | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		m.tags = append(m.tags, nil) | ||||
| 		copy(m.tags[i+1:], m.tags[i:]) | ||||
| 		m.tags[i] = &lp.Tag{Key: key, Value: value} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	m.tags = append(m.tags, &lp.Tag{Key: key, Value: value}) | ||||
| 	m.tags[key] = value | ||||
| } | ||||
|  | ||||
| // HasTag checks if a meta data tag with meta data's key equal to <key> is present in the list of meta data tags | ||||
| func (m *ccMetric) HasMeta(key string) bool { | ||||
| 	for _, tag := range m.meta { | ||||
| 		if tag.Key == key { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| 	_, ok := m.meta[key] | ||||
| 	return ok | ||||
| } | ||||
|  | ||||
| // GetMeta returns the meta data tag with meta data's key equal to <key> | ||||
| func (m *ccMetric) GetMeta(key string) (string, bool) { | ||||
| 	for _, tag := range m.meta { | ||||
| 		if tag.Key == key { | ||||
| 			return tag.Value, true | ||||
| 		} | ||||
| 	} | ||||
| 	return "", false | ||||
| 	value, ok := m.meta[key] | ||||
| 	return value, ok | ||||
| } | ||||
|  | ||||
| // RemoveMeta removes the meta data tag with tag's key equal to <key> | ||||
| // and keeps the meta data tag list ordered by the keys | ||||
| func (m *ccMetric) RemoveMeta(key string) { | ||||
| 	for i, tag := range m.meta { | ||||
| 		if tag.Key == key { | ||||
| 			copy(m.meta[i:], m.meta[i+1:]) | ||||
| 			m.meta[len(m.meta)-1] = nil | ||||
| 			m.meta = m.meta[:len(m.meta)-1] | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	delete(m.meta, key) | ||||
| } | ||||
|  | ||||
| // AddMeta adds a meta data tag (consisting of key and value) | ||||
| // and keeps the meta data list ordered by the keys | ||||
| func (m *ccMetric) AddMeta(key, value string) { | ||||
| 	for i, tag := range m.meta { | ||||
| 		if key > tag.Key { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if key == tag.Key { | ||||
| 			tag.Value = value | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		m.meta = append(m.meta, nil) | ||||
| 		copy(m.meta[i+1:], m.meta[i:]) | ||||
| 		m.meta[i] = &lp.Tag{Key: key, Value: value} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	m.meta = append(m.meta, &lp.Tag{Key: key, Value: value}) | ||||
| 	m.meta[key] = value | ||||
| } | ||||
|  | ||||
| // AddField adds a field (consisting of key and value) to the unordered list of fields | ||||
| @@ -261,62 +210,49 @@ func New( | ||||
| ) (CCMetric, error) { | ||||
| 	m := &ccMetric{ | ||||
| 		name:   name, | ||||
| 		tags:   nil, | ||||
| 		fields: nil, | ||||
| 		tags:   make(map[string]string, len(tags)), | ||||
| 		meta:   make(map[string]string, len(meta)), | ||||
| 		fields: make([]*lp.Field, 0, len(fields)), | ||||
| 		tm:     tm, | ||||
| 		meta:   nil, | ||||
| 	} | ||||
|  | ||||
| 	// Sorted list of tags | ||||
| 	if len(tags) > 0 { | ||||
| 		m.tags = make([]*lp.Tag, 0, len(tags)) | ||||
| 		for k, v := range tags { | ||||
| 			m.tags = append(m.tags, | ||||
| 				&lp.Tag{Key: k, Value: v}) | ||||
| 		} | ||||
| 		sort.Slice(m.tags, func(i, j int) bool { return m.tags[i].Key < m.tags[j].Key }) | ||||
| 	// deep copy tags | ||||
| 	for k, v := range tags { | ||||
| 		m.tags[k] = v | ||||
| 	} | ||||
|  | ||||
| 	// Sorted list of meta data tags | ||||
| 	if len(meta) > 0 { | ||||
| 		m.meta = make([]*lp.Tag, 0, len(meta)) | ||||
| 		for k, v := range meta { | ||||
| 			m.meta = append(m.meta, | ||||
| 				&lp.Tag{Key: k, Value: v}) | ||||
| 		} | ||||
| 		sort.Slice(m.meta, func(i, j int) bool { return m.meta[i].Key < m.meta[j].Key }) | ||||
| 	// deep copy meta data tags | ||||
| 	for k, v := range meta { | ||||
| 		m.meta[k] = v | ||||
| 	} | ||||
|  | ||||
| 	// Unsorted list of fields | ||||
| 	if len(fields) > 0 { | ||||
| 		m.fields = make([]*lp.Field, 0, len(fields)) | ||||
| 		for k, v := range fields { | ||||
| 			v := convertField(v) | ||||
| 			if v == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			m.AddField(k, v) | ||||
| 	for k, v := range fields { | ||||
| 		v := convertField(v) | ||||
| 		if v == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		m.AddField(k, v) | ||||
| 	} | ||||
|  | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| // FromMetric copies the metric <other> | ||||
| func FromMetric(other CCMetric) CCMetric { | ||||
| func FromMetric(other ccMetric) CCMetric { | ||||
| 	m := &ccMetric{ | ||||
| 		name:   other.Name(), | ||||
| 		tags:   make([]*lp.Tag, len(other.TagList())), | ||||
| 		tags:   make(map[string]string), | ||||
| 		fields: make([]*lp.Field, len(other.FieldList())), | ||||
| 		meta:   make([]*lp.Tag, len(other.MetaList())), | ||||
| 		meta:   make(map[string]string), | ||||
| 		tm:     other.Time(), | ||||
| 	} | ||||
|  | ||||
| 	for i, tag := range other.TagList() { | ||||
| 		m.tags[i] = &lp.Tag{Key: tag.Key, Value: tag.Value} | ||||
| 	for key, value := range other.Tags() { | ||||
| 		m.tags[key] = value | ||||
| 	} | ||||
| 	for i, s := range other.MetaList() { | ||||
| 		m.meta[i] = &lp.Tag{Key: s.Key, Value: s.Value} | ||||
| 	for key, value := range other.Meta() { | ||||
| 		m.meta[key] = value | ||||
| 	} | ||||
|  | ||||
| 	for i, field := range other.FieldList() { | ||||
| @@ -329,17 +265,14 @@ func FromMetric(other CCMetric) CCMetric { | ||||
| func FromInfluxMetric(other lp.Metric) CCMetric { | ||||
| 	m := &ccMetric{ | ||||
| 		name:   other.Name(), | ||||
| 		tags:   make([]*lp.Tag, len(other.TagList())), | ||||
| 		tags:   make(map[string]string), | ||||
| 		fields: make([]*lp.Field, len(other.FieldList())), | ||||
| 		meta:   make([]*lp.Tag, 0), | ||||
| 		meta:   make(map[string]string), | ||||
| 		tm:     other.Time(), | ||||
| 	} | ||||
|  | ||||
| 	for i, otherTag := range other.TagList() { | ||||
| 		m.tags[i] = &lp.Tag{ | ||||
| 			Key:   otherTag.Key, | ||||
| 			Value: otherTag.Value, | ||||
| 		} | ||||
| 	for _, otherTag := range other.TagList() { | ||||
| 		m.tags[otherTag.Key] = otherTag.Value | ||||
| 	} | ||||
|  | ||||
| 	for i, otherField := range other.FieldList() { | ||||
|   | ||||
| @@ -141,11 +141,11 @@ func (r *metricRouter) EvalCondition(cond string, point lp.CCMetric) (bool, erro | ||||
| 	// Add metric name, tags, meta data, fields and timestamp to the parameter list | ||||
| 	params := make(map[string]interface{}) | ||||
| 	params["name"] = point.Name() | ||||
| 	for _, t := range point.TagList() { | ||||
| 		params[t.Key] = t.Value | ||||
| 	for key, value := range point.Tags() { | ||||
| 		params[key] = value | ||||
| 	} | ||||
| 	for _, m := range point.MetaList() { | ||||
| 		params[m.Key] = m.Value | ||||
| 	for key, value := range point.Meta() { | ||||
| 		params[key] = value | ||||
| 	} | ||||
| 	for _, f := range point.FieldList() { | ||||
| 		params[f.Key] = f.Value | ||||
|   | ||||
| @@ -30,16 +30,16 @@ func (s *GangliaSink) Write(point lp.CCMetric) error { | ||||
| 	var err error = nil | ||||
| 	var tagsstr []string | ||||
| 	var argstr []string | ||||
| 	for _, t := range point.TagList() { | ||||
| 		switch t.Key { | ||||
| 	for key, value := range point.Tags() { | ||||
| 		switch key { | ||||
| 		case "cluster": | ||||
| 			argstr = append(argstr, fmt.Sprintf("--cluster=%s", t.Value)) | ||||
| 			argstr = append(argstr, fmt.Sprintf("--cluster=%s", value)) | ||||
| 		case "unit": | ||||
| 			argstr = append(argstr, fmt.Sprintf("--units=%s", t.Value)) | ||||
| 			argstr = append(argstr, fmt.Sprintf("--units=%s", value)) | ||||
| 		case "group": | ||||
| 			argstr = append(argstr, fmt.Sprintf("--group=%s", t.Value)) | ||||
| 			argstr = append(argstr, fmt.Sprintf("--group=%s", value)) | ||||
| 		default: | ||||
| 			tagsstr = append(tagsstr, fmt.Sprintf("%s=%s", t.Key, t.Value)) | ||||
| 			tagsstr = append(tagsstr, fmt.Sprintf("%s=%s", key, value)) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(tagsstr) > 0 { | ||||
|   | ||||
| @@ -5,10 +5,11 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
|  | ||||
| 	lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" | ||||
| 	influxdb2 "github.com/influxdata/influxdb-client-go/v2" | ||||
| 	influxdb2Api "github.com/influxdata/influxdb-client-go/v2/api" | ||||
| 	"log" | ||||
| ) | ||||
|  | ||||
| type InfluxSink struct { | ||||
| @@ -61,12 +62,12 @@ func (s *InfluxSink) Init(config sinkConfig) error { | ||||
| func (s *InfluxSink) Write(point lp.CCMetric) error { | ||||
| 	tags := map[string]string{} | ||||
| 	fields := map[string]interface{}{} | ||||
| 	for _, t := range point.TagList() { | ||||
| 		tags[t.Key] = t.Value | ||||
| 	for key, value := range point.Tags() { | ||||
| 		tags[key] = value | ||||
| 	} | ||||
| 	if s.meta_as_tags { | ||||
| 		for _, m := range point.MetaList() { | ||||
| 			tags[m.Key] = m.Value | ||||
| 		for key, value := range point.Meta() { | ||||
| 			tags[key] = value | ||||
| 		} | ||||
| 	} | ||||
| 	for _, f := range point.FieldList() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user