-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
633 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//go:build kubeapiserver | ||
|
||
/* | ||
Package loadstore stores local failover metrics for the workload that need autoscaling | ||
*/ | ||
package loadstore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//go:build kubeapiserver | ||
|
||
package loadstore | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
"unsafe" | ||
) | ||
|
||
// EntityType defines the type of entity. | ||
type EntityType int | ||
|
||
// ValueType defines the datatype of metric value. | ||
type ValueType float64 | ||
|
||
// Enumeration of entity types. | ||
const ( | ||
ContainerType EntityType = iota | ||
UnknownType | ||
) | ||
|
||
const ( | ||
// maxDataPoints is the maximum number of data points to store per entity. | ||
maxDataPoints = 3 | ||
// defaultPurgeInterval is the default interval to purge inactive entities. | ||
defaultPurgeInterval = 3 * time.Minute | ||
// defaultExpireInterval is the default interval to expire entities. | ||
defaultExpireInterval = 3 * time.Minute | ||
) | ||
|
||
// Entity represents an entity with a type and its attributes. | ||
type Entity struct { | ||
EntityType EntityType | ||
SourceID string | ||
Host string // serie.Host | ||
EntityName string // display_container_name | ||
Namespace string | ||
MetricName string | ||
} | ||
|
||
// String returns a string representation of the Entity. | ||
func (e *Entity) String() string { | ||
return fmt.Sprintf( | ||
" Key: %d,"+ | ||
" SourceID: %s,"+ | ||
" MetricName: %s"+ | ||
" EntityName: %s,"+ | ||
" EntityType: %d,"+ | ||
" Host: %s,"+ | ||
" Namespace: %s", | ||
hashEntityToUInt64(e), e.SourceID, e.MetricName, e.EntityName, e.EntityType, e.Host, e.Namespace) | ||
} | ||
|
||
// MemoryUsage returns the memory usage of the entity in bytes. | ||
func (e *Entity) MemoryUsage() uint32 { | ||
return uint32(len(e.SourceID)) + uint32(len(e.Host)) + uint32(len(e.EntityName)) + uint32(len(e.Namespace)) + uint32(len(e.MetricName)) + uint32(unsafe.Sizeof(e.EntityType)) | ||
} | ||
|
||
// EntityValue represents a metric value with a timestamp. | ||
type EntityValue struct { | ||
value ValueType | ||
timestamp Timestamp | ||
} | ||
|
||
// String returns a string representation of the EntityValue. | ||
func (ev *EntityValue) String() string { | ||
// Convert the timestamp to a time.Time object assuming the timestamp is in seconds. | ||
// If the timestamp is in milliseconds, use time.UnixMilli(ev.timestamp) instead. | ||
readableTime := time.Unix(int64(ev.timestamp), 0).Local().Format(time.RFC3339) | ||
return fmt.Sprintf("Value: %f, Timestamp: %s", ev.value, readableTime) | ||
} |
115 changes: 115 additions & 0 deletions
115
pkg/clusteragent/autoscaling/workload/loadstore/store.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//go:build kubeapiserver | ||
|
||
package loadstore | ||
|
||
import ( | ||
"math" | ||
"strings" | ||
|
||
"github.com/DataDog/agent-payload/v5/gogen" | ||
) | ||
|
||
// StoreInfo represents the store information, like memory usage and entity count. | ||
type StoreInfo struct { | ||
TotalMemoryUsage uint64 | ||
TotalEntityCount uint64 | ||
currentTime Timestamp | ||
EntityCountByMetric map[string]uint64 | ||
EntityCountByNamespace map[string]uint64 | ||
} | ||
|
||
// Store is an interface for in-memory storage of entities and their load metric values. | ||
type Store interface { | ||
// SetEntitiesValues sets the values for the given map | ||
SetEntitiesValues(entities map[*Entity]*EntityValue) | ||
|
||
// GetStoreInfo returns the store information. | ||
GetStoreInfo() StoreInfo | ||
|
||
// GetEntitiesByNamespace to get all entities and values by namespace | ||
GetEntitiesByNamespace(namespace string) map[*Entity]*EntityValue | ||
|
||
// GetEntitiesByMetricName to get all entities and values by load metric name | ||
GetEntitiesByMetricName(metricName string) map[*Entity]*EntityValue | ||
|
||
// GetAllMetricNamesWithCount to get all metric names and corresponding entity count | ||
GetAllMetricNamesWithCount() map[string]int64 | ||
|
||
// GetAllNamespaceNamesWithCount to get all namespace names and corresponding entity count | ||
GetAllNamespaceNamesWithCount() map[string]int64 | ||
|
||
// GetEntityByHashKey to get entity and latest value by hash key | ||
GetEntityByHashKey(hash uint64) (*Entity, *EntityValue) | ||
|
||
//DeleteEntityByHashKey to delete entity by hash key | ||
DeleteEntityByHashKey(hash uint64) | ||
} | ||
|
||
// createEntitiesFromPayload is a helper function used for creating entities from the metric payload. | ||
func createEntitiesFromPayload(payload *gogen.MetricPayload) map[*Entity]*EntityValue { | ||
entities := make(map[*Entity]*EntityValue) | ||
splitTag := func(tag string) (key string, value string) { | ||
split := strings.SplitN(tag, ":", 2) | ||
if len(split) < 2 || split[0] == "" || split[1] == "" { | ||
return "", "" | ||
} | ||
return split[0], split[1] | ||
} | ||
for _, series := range payload.Series { | ||
metricName := series.GetMetric() | ||
points := series.GetPoints() | ||
tags := series.GetTags() | ||
resources := series.GetResources() | ||
entity := Entity{ | ||
EntityType: UnknownType, | ||
SourceID: "", | ||
Host: "", | ||
EntityName: "", | ||
Namespace: "", | ||
MetricName: metricName, | ||
} | ||
for _, resource := range resources { | ||
if resource.Type == "host" { | ||
entity.Host = resource.Name | ||
} | ||
} | ||
for _, tag := range tags { | ||
k, v := splitTag(tag) | ||
switch k { | ||
case "display_container_name": | ||
entity.EntityName = v | ||
case "kube_namespace": | ||
entity.Namespace = v | ||
case "container_id": | ||
entity.SourceID = v | ||
entity.EntityType = ContainerType | ||
} | ||
} | ||
if entity.MetricName == "" || entity.Host == "" || entity.EntityType == UnknownType || entity.Namespace == "" || entity.SourceID == "" { | ||
continue | ||
} | ||
for _, point := range points { | ||
if point != nil && !math.IsNaN(point.Value) { | ||
entities[&entity] = &EntityValue{ | ||
value: ValueType(point.Value), | ||
timestamp: Timestamp(point.Timestamp), | ||
} | ||
} | ||
} | ||
} | ||
return entities | ||
} | ||
|
||
// ProcessLoadPayload converts the metric payload and stores the entities and their values in the store. | ||
func ProcessLoadPayload(payload *gogen.MetricPayload, store Store) { | ||
if payload == nil || store == nil { | ||
return | ||
} | ||
entities := createEntitiesFromPayload(payload) | ||
store.SetEntitiesValues(entities) | ||
} |
Oops, something went wrong.