Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ func createExporter(opts component.Options, args component.Arguments) (integrati
fipsEnabled := !a.FIPSDisabled

if a.DecoupledScrape.Enabled {
exp, err := cloudwatch_exporter.NewDecoupledCloudwatchExporter(opts.ID, opts.Logger, exporterConfig, a.DecoupledScrape.ScrapeInterval, fipsEnabled, a.Debug, a.UseAWSSDKVersion2)
exp, err := cloudwatch_exporter.NewDecoupledCloudwatchExporter(opts.ID, opts.Logger, exporterConfig, a.DecoupledScrape.ScrapeInterval, fipsEnabled, a.LabelsSnakeCase, a.Debug, a.UseAWSSDKVersion2)
return exp, getHash(a), err
}

exp, err := cloudwatch_exporter.NewCloudwatchExporter(opts.ID, opts.Logger, exporterConfig, fipsEnabled, a.Debug, a.UseAWSSDKVersion2)
exp, err := cloudwatch_exporter.NewCloudwatchExporter(opts.ID, opts.Logger, exporterConfig, fipsEnabled, a.LabelsSnakeCase, a.Debug, a.UseAWSSDKVersion2)
return exp, getHash(a), err
}
95 changes: 65 additions & 30 deletions internal/component/prometheus/exporter/cloudwatch/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/grafana/alloy/syntax"
)

// Avoid producing absence of values in metrics
// Avoid producing absence of values in metrics.
var defaultNilToZero = true

var defaults = Arguments{
Expand All @@ -26,6 +26,7 @@ var defaults = Arguments{
Enabled: false,
ScrapeInterval: 5 * time.Minute,
},
LabelsSnakeCase: false,
UseAWSSDKVersion2: false,
}

Expand All @@ -39,6 +40,7 @@ type Arguments struct {
Static []StaticJob `alloy:"static,block,optional"`
CustomNamespace []CustomNamespaceJob `alloy:"custom_namespace,block,optional"`
DecoupledScrape DecoupledScrapeConfig `alloy:"decoupled_scraping,block,optional"`
LabelsSnakeCase bool `alloy:"labels_snake_case,attr,optional"`
UseAWSSDKVersion2 bool `alloy:"aws_sdk_version_v2,attr,optional"`
}

Expand All @@ -60,9 +62,11 @@ type DiscoveryJob struct {
DimensionNameRequirements []string `alloy:"dimension_name_requirements,attr,optional"`
RecentlyActiveOnly bool `alloy:"recently_active_only,attr,optional"`
Metrics []Metric `alloy:"metric,block"`
Period time.Duration `alloy:"period,attr,optional"`
Length time.Duration `alloy:"length,attr,optional"`
Delay time.Duration `alloy:"delay,attr,optional"`
//TODO: Remove NilToZero, because it is deprecated upstream.
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
AddCloudwatchTimestamp *bool `alloy:"add_cloudwatch_timestamp,attr,optional"`
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
}

// Tags represents a series of tags configured on an AWS resource. Each tag is a
Expand All @@ -77,8 +81,14 @@ type StaticJob struct {
Namespace string `alloy:"namespace,attr"`
Dimensions Dimensions `alloy:"dimensions,attr"`
Metrics []Metric `alloy:"metric,block"`
Period time.Duration `alloy:"period,attr,optional"`
Length time.Duration `alloy:"length,attr,optional"`
Delay time.Duration `alloy:"delay,attr,optional"`
//TODO: Remove NilToZero, because it is deprecated upstream.
// NOTE: This field is actually not supported as a job level configuration option in YACE!
// https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/0c9677d91836f0a4150a55172a0ce5081574b407/docs/configuration.md?plain=1#L177
// It should either be removed from Alloy in some major release, or
// contributed to YACE.
// We currently patch it in toStaticJob func to make it work and not break existing configs.
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
}

Expand All @@ -91,8 +101,10 @@ type CustomNamespaceJob struct {
RecentlyActiveOnly bool `alloy:"recently_active_only,attr,optional"`
Metrics []Metric `alloy:"metric,block"`
Delay time.Duration `alloy:"delay,attr,optional"`
//TODO: Remove NilToZero, because it is deprecated upstream.
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
Period time.Duration `alloy:"period,attr,optional"`
Length time.Duration `alloy:"length,attr,optional"`
AddCloudwatchTimestamp *bool `alloy:"add_cloudwatch_timestamp,attr,optional"`
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
}

// RegionAndRoles exposes for each supported job, the AWS regions and IAM roles
Expand All @@ -114,7 +126,7 @@ type Dimensions map[string]string
type Metric struct {
Name string `alloy:"name,attr"`
Statistics []string `alloy:"statistics,attr"`
Period time.Duration `alloy:"period,attr"`
Period time.Duration `alloy:"period,attr,optional"`
Length time.Duration `alloy:"length,attr,optional"`
NilToZero *bool `alloy:"nil_to_zero,attr,optional"`
AddCloudwatchTimestamp *bool `alloy:"add_cloudwatch_timestamp,attr,optional"`
Expand Down Expand Up @@ -243,19 +255,29 @@ func toYACERoles(rs []Role) []yaceConf.Role {
return yaceRoles
}

func toYACEMetrics(ms []Metric, jobNilToZero *bool) []*yaceConf.Metric {
func toYACEMetrics(ms []Metric, jobPeriod time.Duration, jobLength time.Duration) []*yaceConf.Metric {
yaceMetrics := []*yaceConf.Metric{}
for _, m := range ms {
if m.Period == 0 {
m.Period = jobPeriod
}
if m.Length == 0 {
m.Length = jobLength
}

periodSeconds := int64(m.Period.Seconds())
lengthSeconds := periodSeconds
// If length is other than zero, that is, it is configured, override the default period value
// If length is other than zero, that is, it is configured, override the default length value
if m.Length != 0 {
lengthSeconds = int64(m.Length.Seconds())
}
nilToZero := m.NilToZero
if nilToZero == nil {
nilToZero = jobNilToZero
}

/* Scenarios:
- Period and length are zero (not set) -> Period = "5m", Length = "5m". These defaults are set by YACE.
- Period = 1m, Length = 0m -> Period = "1m", Length = "1m". Length is set equal to Period by this function.
- Period = 0, Length = 10m -> Period = "5m", Length = "10m". Period is set to the default value by YACE.
- Period = 10m, Length = 2m -> Period = "10m", Length = "2m". This is not a valid configuration and will cause an error produced by YACE. See https://github.com/prometheus-community/yet-another-cloudwatch-exporter/blob/292db29c1537af84a5e831b007bc9ff501708eaa/pkg/config/config.go#L390
*/
yaceMetrics = append(yaceMetrics, &yaceConf.Metric{
Name: m.Name,
Statistics: m.Statistics,
Expand All @@ -268,7 +290,7 @@ func toYACEMetrics(ms []Metric, jobNilToZero *bool) []*yaceConf.Metric {
Period: periodSeconds,
Length: lengthSeconds,

NilToZero: nilToZero,
NilToZero: m.NilToZero,
AddCloudwatchTimestamp: m.AddCloudwatchTimestamp,
})
}
Expand All @@ -283,22 +305,32 @@ func toYACEStaticJob(sj StaticJob) *yaceConf.Static {
Value: value,
})
}
nilToZero := sj.NilToZero
if nilToZero == nil {
nilToZero = &defaultNilToZero

// For each metric in sj.Metrics, if NilToZero is not set, set the NilToZero to the job level NilToZero or DefaultNilToZero.
// This is needed to make the `nil_to_zero` job level option work in static jobs as this is not natively supported by YACE.
for i, m := range sj.Metrics {
if m.NilToZero == nil {
if sj.NilToZero == nil {
sj.Metrics[i].NilToZero = &defaultNilToZero
} else {
sj.Metrics[i].NilToZero = sj.NilToZero
}
}
}

return &yaceConf.Static{
Name: sj.Name,
Regions: sj.Auth.Regions,
Roles: toYACERoles(sj.Auth.Roles),
Namespace: sj.Namespace,
CustomTags: sj.CustomTags.toYACE(),
Dimensions: dims,
Metrics: toYACEMetrics(sj.Metrics, nilToZero),
Metrics: toYACEMetrics(sj.Metrics, 0, 0),
}
}

func toYACEDiscoveryJob(rj DiscoveryJob) *yaceConf.Job {
// The default of YACE is false, but for Alloy we want to default to true.
nilToZero := rj.NilToZero
if nilToZero == nil {
nilToZero = &defaultNilToZero
Expand All @@ -310,19 +342,21 @@ func toYACEDiscoveryJob(rj DiscoveryJob) *yaceConf.Job {
CustomTags: rj.CustomTags.toYACE(),
SearchTags: rj.SearchTags.toYACE(),
DimensionNameRequirements: rj.DimensionNameRequirements,
// By setting RoundingPeriod to nil, the exporter will align the start and end times for retrieving CloudWatch
// metrics, with the smallest period in the retrieved batch.
RoundingPeriod: nil,
RecentlyActiveOnly: rj.RecentlyActiveOnly,
RecentlyActiveOnly: rj.RecentlyActiveOnly,
JobLevelMetricFields: yaceConf.JobLevelMetricFields{
Delay: int64(rj.Delay.Seconds()),
AddCloudwatchTimestamp: rj.AddCloudwatchTimestamp,
Period: int64(rj.Period.Seconds()),
Length: int64(rj.Length.Seconds()),
Delay: int64(rj.Delay.Seconds()),
NilToZero: nilToZero,
},
Metrics: toYACEMetrics(rj.Metrics, nilToZero),
Metrics: toYACEMetrics(rj.Metrics, rj.Period, rj.Length),
}
return job
}

func toYACECustomNamespaceJob(cn CustomNamespaceJob) *yaceConf.CustomNamespace {
// The default of YACE is false, but for Alloy we want to default to true.
nilToZero := cn.NilToZero
if nilToZero == nil {
nilToZero = &defaultNilToZero
Expand All @@ -334,14 +368,15 @@ func toYACECustomNamespaceJob(cn CustomNamespaceJob) *yaceConf.CustomNamespace {
Roles: toYACERoles(cn.Auth.Roles),
CustomTags: cn.CustomTags.toYACE(),
DimensionNameRequirements: cn.DimensionNameRequirements,
// By setting RoundingPeriod to nil, the exporter will align the start and end times for retrieving CloudWatch
// metrics, with the smallest period in the retrieved batch.
RoundingPeriod: nil,
RecentlyActiveOnly: cn.RecentlyActiveOnly,
RecentlyActiveOnly: cn.RecentlyActiveOnly,
JobLevelMetricFields: yaceConf.JobLevelMetricFields{
Delay: int64(cn.Delay.Seconds()),
AddCloudwatchTimestamp: cn.AddCloudwatchTimestamp,
Period: int64(cn.Period.Seconds()),
Length: int64(cn.Length.Seconds()),
Delay: int64(cn.Delay.Seconds()),
NilToZero: nilToZero,
},
Metrics: toYACEMetrics(cn.Metrics, nilToZero),
Metrics: toYACEMetrics(cn.Metrics, cn.Period, cn.Length),
}
}

Expand Down
Loading
Loading