diff --git a/pkg/aws/ec2/ec2.go b/pkg/aws/ec2/ec2.go index 2e03e308..d9acb2e0 100644 --- a/pkg/aws/ec2/ec2.go +++ b/pkg/aws/ec2/ec2.go @@ -9,6 +9,8 @@ import ( "sync" "time" + "github.com/grafana/cloudcost-exporter/pkg/utils" + ec2Types "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sync/errgroup" @@ -32,29 +34,33 @@ var ( ) var ( - InstanceCPUHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "instance_cpu_usd_per_core_hour"), + InstanceCPUHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.InstanceCPUCostSuffix, "The cpu cost a ec2 instance in USD/(core*h)", []string{"instance", "instance_id", "region", "family", "machine_type", "cluster_name", "price_tier"}, - nil, ) - InstanceMemoryHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "instance_memory_usd_per_gib_hour"), + InstanceMemoryHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.InstanceMemoryCostSuffix, "The memory cost of a ec2 instance in USD/(GiB*h)", []string{"instance", "instance_id", "region", "family", "machine_type", "cluster_name", "price_tier"}, - nil, ) - InstanceTotalHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "instance_total_usd_per_hour"), + InstanceTotalHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.InstanceTotalCostSuffix, "The total cost of the ec2 instance in USD/h", []string{"instance", "instance_id", "region", "family", "machine_type", "cluster_name", "price_tier"}, - nil, ) - PersistentVolumeHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "persistent_volume_usd_per_hour"), + PersistentVolumeHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.PersistentVolumeCostSuffix, "The cost of an AWS EBS Volume in USD/h.", []string{"persistentvolume", "region", "availability_zone", "disk", "type", "size_gib", "state"}, - nil, ) ) diff --git a/pkg/azure/aks/aks.go b/pkg/azure/aks/aks.go index 5e8bd105..dc36c4c4 100644 --- a/pkg/azure/aks/aks.go +++ b/pkg/azure/aks/aks.go @@ -7,6 +7,8 @@ import ( "log/slog" "time" + "github.com/grafana/cloudcost-exporter/pkg/utils" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/prometheus/client_golang/prometheus" @@ -58,23 +60,26 @@ var ( // Prometheus Metrics var ( - InstanceCPUHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_cpu_usd_per_core_hour"), - "The cpu cost a compute instance in USD/(core*h)", + InstanceCPUHourlyCostDesc = utils.GenerateDesc( + cloudcost_exporter.MetricPrefix, + subsystem, + utils.InstanceCPUCostSuffix, + "The cpu cost a a compute instance in USD/(core*h)", []string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"}, - nil, ) - InstanceMemoryHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_memory_usd_per_gib_hour"), + InstanceMemoryHourlyCostDesc = utils.GenerateDesc( + cloudcost_exporter.MetricPrefix, + subsystem, + utils.InstanceMemoryCostSuffix, "The memory cost of a compute instance in USD/(GiB*h)", []string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"}, - nil, ) - InstanceTotalHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_total_usd_per_hour"), - "The total cost of an compute instance in USD/h", + InstanceTotalHourlyCostDesc = utils.GenerateDesc( + cloudcost_exporter.MetricPrefix, + subsystem, + utils.InstanceTotalCostSuffix, + "The total cost of a compute instance in USD/h", []string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"}, - nil, ) ) diff --git a/pkg/google/gke/gke.go b/pkg/google/gke/gke.go index 6d592d42..582b1f4a 100644 --- a/pkg/google/gke/gke.go +++ b/pkg/google/gke/gke.go @@ -9,6 +9,8 @@ import ( "sync" "time" + "github.com/grafana/cloudcost-exporter/pkg/utils" + billingv1 "cloud.google.com/go/billing/apiv1" "github.com/prometheus/client_golang/prometheus" "google.golang.org/api/compute/v1" @@ -22,26 +24,28 @@ const ( ) var ( - gkeNodeMemoryHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "instance_memory_usd_per_gib_hour"), - - "The cpu cost a GKE Instance in USD/(core*h)", - // Cannot simply do cluster because many metric scrapers will add a label for cluster and would interfere with the label we want to add + gkeNodeMemoryHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.InstanceMemoryCostSuffix, + "The memory cost of a GKE Instance in USD/(GiB*h)", + // Cannot simply use "cluster" because other metric scrapers may add a label for cluster, which would interfere []string{"cluster_name", "instance", "region", "family", "machine_type", "project", "price_tier"}, - nil, ) - gkeNodeCPUHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "instance_cpu_usd_per_core_hour"), - "The memory cost of a GKE Instance in USD/(GiB*h)", - // Cannot simply do cluster because many metric scrapers will add a label for cluster and would interfere with the label we want to add + gkeNodeCPUHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.InstanceCPUCostSuffix, + "The CPU cost of a GKE Instance in USD/(core*h)", + // Cannot simply use "cluster" because other metric scrapers may add a label for cluster, which would interfere []string{"cluster_name", "instance", "region", "family", "machine_type", "project", "price_tier"}, - nil, ) - persistentVolumeHourlyCostDesc = prometheus.NewDesc( - prometheus.BuildFQName(cloudcostexporter.MetricPrefix, subsystem, "persistent_volume_usd_per_hour"), - "The cost of a GKE Persistent Volume in USD.", + persistentVolumeHourlyCostDesc = utils.GenerateDesc( + cloudcostexporter.MetricPrefix, + subsystem, + utils.PersistentVolumeCostSuffix, + "The cost of a GKE Persistent Volume in USD/h", []string{"cluster_name", "namespace", "persistentvolume", "region", "project", "storage_class", "disk_type", "use_status"}, - nil, ) ) diff --git a/pkg/utils/consts.go b/pkg/utils/consts.go index 6c69af11..d5425ef8 100644 --- a/pkg/utils/consts.go +++ b/pkg/utils/consts.go @@ -1,5 +1,20 @@ package utils +import "github.com/prometheus/client_golang/prometheus" + const ( - HoursInMonth = 24.35 * 30 // 24.35 is the average amount of hours in a day over a year + HoursInMonth = 24.35 * 30 // 24.35 is the average amount of hours in a day over a year + InstanceCPUCostSuffix = "instance_cpu_usd_per_core_hour" + InstanceMemoryCostSuffix = "instance_memory_usd_per_gib_hour" + InstanceTotalCostSuffix = "instance_total_usd_per_hour" + PersistentVolumeCostSuffix = "persistent_volume_usd_per_hour" ) + +func GenerateDesc(prefix, subsystem, suffix, description string, labels []string) *prometheus.Desc { + return prometheus.NewDesc( + prometheus.BuildFQName(prefix, subsystem, suffix), + description, + labels, + nil, + ) +} diff --git a/pkg/utils/consts_test.go b/pkg/utils/consts_test.go new file mode 100644 index 00000000..f4e247fc --- /dev/null +++ b/pkg/utils/consts_test.go @@ -0,0 +1,35 @@ +package utils + +import ( + "strings" + "testing" + + "github.com/prometheus/client_golang/prometheus" +) + +func TestGenerateDesc(t *testing.T) { + prefix := "test_prefix" + subsystem := "test_subsystem" + suffix := "test_suffix" + description := "This is a test description" + labels := []string{"label1", "label2"} + + desc := GenerateDesc(prefix, subsystem, suffix, description, labels) + + // Expected values + expectedFQName := prometheus.BuildFQName(prefix, subsystem, suffix) + + if !strings.Contains(desc.String(), expectedFQName) { + t.Errorf("Expected FQName %s in desc, but got %s", expectedFQName, desc.String()) + } + + if !strings.Contains(desc.String(), description) { + t.Errorf("Expected description %s in desc, but got %s", description, desc.String()) + } + + for _, label := range labels { + if !strings.Contains(desc.String(), label) { + t.Errorf("Expected label %s in desc, but got %s", label, desc.String()) + } + } +}