@@ -91,60 +91,6 @@ func NewPrometheusClient(parentLogger logger.Logger, prometheusURL, namespace st
9191 }, nil
9292}
9393
94- // renderQuery renders the Prometheus query template
95- func (pc * PrometheusClient ) renderQuery (queryTemplate * template.Template , windowSize , resourceNameRegex string ) (string , error ) {
96- templateData := make (map [string ]string )
97- templateData ["Namespace" ] = pc .namespace
98- templateData ["WindowSize" ] = windowSize
99- templateData ["Resources" ] = resourceNameRegex
100-
101- var queryBuffer bytes.Buffer
102- if err := queryTemplate .Execute (& queryBuffer , templateData ); err != nil {
103- return "" , fmt .Errorf ("error executing template: %w" , err )
104- }
105-
106- return queryBuffer .String (), nil
107- }
108-
109- // extractWindowSizesForMetric extracts unique window sizes from resources' ScaleResources for a specific metric name.
110- func (pc * PrometheusClient ) extractWindowSizesForMetric (resources []scalertypes.Resource , metricName string ) map [string ]bool {
111- windowSizes := make (map [string ]bool )
112- for _ , resource := range resources {
113- for _ , scaleResource := range resource .ScaleResources {
114- if scaleResource .MetricName == metricName {
115- windowSizeStr := scalertypes .ShortDurationString (scaleResource .WindowSize )
116- windowSizes [windowSizeStr ] = true
117- }
118- }
119- }
120- return windowSizes
121- }
122-
123- // buildResourceNameRegex creates a pipe-separated regex pattern from resource names for Prometheus query filtering (e.g., "func1|func2|func3")
124- func (pc * PrometheusClient ) buildResourceNameRegex (resources []scalertypes.Resource ) string {
125- resourceNames := make ([]string , len (resources ))
126- for i , resource := range resources {
127- resourceNames [i ] = resource .Name
128- }
129- return strings .Join (resourceNames , "|" )
130- }
131-
132- // resolveFullMetricName finds the matching ScaleResource for a given metric name and window size,
133- // and returns the full metric name (e.g., "metric_name_per_1m").
134- func (pc * PrometheusClient ) resolveFullMetricName (resources []scalertypes.Resource , metricName , windowSize string ) (string , error ) {
135- for _ , resource := range resources {
136- for _ , scaleResource := range resource .ScaleResources {
137- if scaleResource .MetricName == metricName {
138- scaleResourceWindowSize := scalertypes .ShortDurationString (scaleResource .WindowSize )
139- if scaleResourceWindowSize == windowSize {
140- return scaleResource .GetKubernetesMetricName (), nil
141- }
142- }
143- }
144- }
145- return "" , errors .Errorf ("Failed to find ScaleResource matching metric name and window size: metricName=%s, windowSize=%s" , metricName , windowSize )
146- }
147-
14894// GetResourceMetrics retrieves metrics for multiple resources
14995func (pc * PrometheusClient ) GetResourceMetrics (resources []scalertypes.Resource ) (map [string ]map [string ]int , error ) {
15096 metricsByResource := make (map [string ]map [string ]int )
@@ -203,23 +149,23 @@ func (pc *PrometheusClient) GetResourceMetrics(resources []scalertypes.Resource)
203149 for _ , metricSample := range metricSamples {
204150 resourceName , err := pc .extractResourceName (metricSample .Metric )
205151 if err != nil {
206- pc .logger .WarnWith ("Failed to extract resource name from Prometheus metricSample labels" ,
152+ pc .logger .WarnWith ("Failed to extract resource name from the Prometheus metric's labels" ,
207153 "metricName" , metricName ,
208154 "windowSize" , windowSize ,
209155 "labels" , metricSample .Metric .String (),
210156 "error" , err )
211157 continue
212158 }
213159
214- // Use Ceil to ensure any fractional value > 0 becomes at least 1
160+ // Round up values to ensure any fractional value > 0 becomes at least 1
215161 // This prevents incorrect scale-to-zero decisions for resources with low activity
216162 metricValue := int (math .Ceil (float64 (metricSample .Value )))
217163
218164 if _ , found := metricsByResource [resourceName ]; ! found {
219165 metricsByResource [resourceName ] = make (map [string ]int )
220166 }
221167
222- pc .logger .DebugWith ("Retrieved metricSample sample " ,
168+ pc .logger .DebugWith ("Retrieved metric " ,
223169 "resourceName" , resourceName ,
224170 "metricName" , fullMetricName ,
225171 "windowSize" , windowSize ,
@@ -228,29 +174,80 @@ func (pc *PrometheusClient) GetResourceMetrics(resources []scalertypes.Resource)
228174 if _ , found := metricsByResource [resourceName ][fullMetricName ]; found {
229175 return nil , errors .Errorf ("Cannot have more than one metricSample value per resource: resource=%s, metricSample=%s" , resourceName , fullMetricName )
230176 }
231-
232177 metricsByResource [resourceName ][fullMetricName ] = metricValue
233178 }
234179 }
235180 }
236-
237181 return metricsByResource , nil
238182}
239183
184+ // renderQuery renders the Prometheus query template
185+ func (pc * PrometheusClient ) renderQuery (queryTemplate * template.Template , windowSize , resourceNameRegex string ) (string , error ) {
186+ templateData := make (map [string ]string )
187+ templateData ["Namespace" ] = pc .namespace
188+ templateData ["WindowSize" ] = windowSize
189+ templateData ["Resources" ] = resourceNameRegex
190+
191+ var queryBuffer bytes.Buffer
192+ if err := queryTemplate .Execute (& queryBuffer , templateData ); err != nil {
193+ return "" , fmt .Errorf ("error executing template: %w" , err )
194+ }
195+
196+ return queryBuffer .String (), nil
197+ }
198+
199+ // extractWindowSizesForMetric extracts unique window sizes from resources' ScaleResources for a specific metric name.
200+ func (pc * PrometheusClient ) extractWindowSizesForMetric (resources []scalertypes.Resource , metricName string ) map [string ]bool {
201+ windowSizes := make (map [string ]bool )
202+ for _ , resource := range resources {
203+ for _ , scaleResource := range resource .ScaleResources {
204+ if scaleResource .MetricName == metricName {
205+ windowSizeStr := scalertypes .ShortDurationString (scaleResource .WindowSize )
206+ windowSizes [windowSizeStr ] = true
207+ }
208+ }
209+ }
210+ return windowSizes
211+ }
212+
213+ // buildResourceNameRegex creates a Prometheus regex pattern for query filtering
214+ func (pc * PrometheusClient ) buildResourceNameRegex (resources []scalertypes.Resource ) string {
215+ resourceNames := make ([]string , len (resources ))
216+ for i , resource := range resources {
217+ resourceNames [i ] = resource .Name
218+ }
219+ // creates a pipe-separated regex pattern from resource names for Prometheus query filtering (e.g., "resource1|resource2")
220+ return strings .Join (resourceNames , "|" )
221+ }
222+
223+ // resolveFullMetricName resolves the full metric name because the same resource can have multiple
224+ // metrics with the same base name but different window sizes (e.g., "metric_name_per_1m" vs "metric_name_per_5m"),
225+ // and we need unique keys in our internal metrics map to store them separately.
226+ func (pc * PrometheusClient ) resolveFullMetricName (resources []scalertypes.Resource , metricName , windowSize string ) (string , error ) {
227+ for _ , resource := range resources {
228+ for _ , scaleResource := range resource .ScaleResources {
229+ if scaleResource .MetricName == metricName {
230+ scaleResourceWindowSize := scalertypes .ShortDurationString (scaleResource .WindowSize )
231+ if scaleResourceWindowSize == windowSize {
232+ return scaleResource .GetKubernetesMetricName (), nil
233+ }
234+ }
235+ }
236+ }
237+ return "" , errors .Errorf ("Failed to find ScaleResource matching metric name and window size: metricName=%s, windowSize=%s" , metricName , windowSize )
238+ }
239+
240240// extractResourceName extracts the resource name from Prometheus metric labels.
241241func (pc * PrometheusClient ) extractResourceName (labels model.Metric ) (string , error ) {
242242 labelNames := []model.LabelName {
243243 "function" , // For nuclio functions (nuclio_processor_handled_events_total) - maps to nucliofunction resource
244244 "service_name" , // For deployments (num_of_requests, jupyter_kernel_busyness) - maps to deployment resource
245245 "pod" , // For pod-based metrics (DCGM_FI_DEV_GPU_UTIL) - maps to pod resource
246246 }
247-
248247 for _ , labelName := range labelNames {
249248 if value , ok := labels [labelName ]; ok {
250249 return string (value ), nil
251250 }
252251 }
253-
254- // If no common label found, return error
255252 return "" , errors .Errorf ("Could not extract resource name from labels: %v" , labels )
256253}
0 commit comments