Skip to content

Commit

Permalink
Added reusable GenerateDesc function across all providers (#343)
Browse files Browse the repository at this point in the history
Implement a Uniform Approach for Defining Metric Descriptions

**Description:**

- This PR refines the definition of metric descriptions in the `cloudcost-exporter` project by implementing a consistent and uniform approach.

- Added new constants and generic reusable method in utils.

- Changed defining metric across all available providers

- closes #222
  • Loading branch information
ohyesgocool authored Nov 1, 2024
1 parent 1bee25b commit 414f655
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 39 deletions.
30 changes: 18 additions & 12 deletions pkg/aws/ec2/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
)
)

Expand Down
27 changes: 16 additions & 11 deletions pkg/azure/aks/aks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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,
)
)

Expand Down
34 changes: 19 additions & 15 deletions pkg/google/gke/gke.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
)
)

Expand Down
17 changes: 16 additions & 1 deletion pkg/utils/consts.go
Original file line number Diff line number Diff line change
@@ -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,
)
}
35 changes: 35 additions & 0 deletions pkg/utils/consts_test.go
Original file line number Diff line number Diff line change
@@ -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())
}
}
}

0 comments on commit 414f655

Please sign in to comment.