(ctx context.Context, metricList []*wfv1.Prometheus, localScope map[string]string, realTimeScope map[string]func() float64, realTimeOnly bool)
| 4061 | } |
| 4062 | |
| 4063 | func (woc *wfOperationCtx) computeMetrics(ctx context.Context, metricList []*wfv1.Prometheus, localScope map[string]string, realTimeScope map[string]func() float64, realTimeOnly bool) { |
| 4064 | for _, metricTmpl := range metricList { |
| 4065 | |
| 4066 | // Don't process real time metrics after execution |
| 4067 | if realTimeOnly && !metricTmpl.IsRealtime() { |
| 4068 | continue |
| 4069 | } |
| 4070 | |
| 4071 | if metricTmpl.Help == "" { |
| 4072 | woc.reportMetricEmissionError(ctx, fmt.Sprintf("metric '%s' must contain a help string under 'help: ' field", metricTmpl.Name)) |
| 4073 | continue |
| 4074 | } |
| 4075 | |
| 4076 | // Substitute parameters in non-value fields of the template to support variables in places such as labels, |
| 4077 | // name, and help. We do not substitute value fields here (i.e. gauge, histogram, counter) here because they |
| 4078 | // might be realtime ({{workflow.duration}} will not be substituted the same way if it's realtime or if it isn't). |
| 4079 | metricTmplBytes, err := json.Marshal(metricTmpl) |
| 4080 | if err != nil { |
| 4081 | woc.reportMetricEmissionError(ctx, fmt.Sprintf("unable to substitute parameters for metric '%s' (marshal): %s", metricTmpl.Name, err)) |
| 4082 | continue |
| 4083 | } |
| 4084 | replacedValue, err := template.Replace(ctx, string(metricTmplBytes), localScope, false) |
| 4085 | if err != nil { |
| 4086 | woc.reportMetricEmissionError(ctx, fmt.Sprintf("unable to substitute parameters for metric '%s': %s", metricTmpl.Name, err)) |
| 4087 | continue |
| 4088 | } |
| 4089 | |
| 4090 | var metricTmplSubstituted wfv1.Prometheus |
| 4091 | err = json.Unmarshal([]byte(replacedValue), &metricTmplSubstituted) |
| 4092 | if err != nil { |
| 4093 | woc.reportMetricEmissionError(ctx, fmt.Sprintf("unable to substitute parameters for metric '%s' (unmarshal): %s", metricTmpl.Name, err)) |
| 4094 | continue |
| 4095 | } |
| 4096 | // Only substitute non-value fields here. Value field substitution happens below |
| 4097 | metricTmpl.Name = metricTmplSubstituted.Name |
| 4098 | metricTmpl.Help = metricTmplSubstituted.Help |
| 4099 | metricTmpl.Labels = metricTmplSubstituted.Labels |
| 4100 | metricTmpl.When = metricTmplSubstituted.When |
| 4101 | |
| 4102 | proceed, err := shouldExecute(metricTmpl.When) |
| 4103 | if err != nil { |
| 4104 | woc.reportMetricEmissionError(ctx, fmt.Sprintf("unable to compute 'when' clause for metric '%s': %s", woc.wf.Name, err)) |
| 4105 | continue |
| 4106 | } |
| 4107 | if !proceed { |
| 4108 | continue |
| 4109 | } |
| 4110 | |
| 4111 | if metricTmpl.IsRealtime() { |
| 4112 | // Finally substitute value parameters |
| 4113 | value := metricTmpl.Gauge.Value |
| 4114 | if !strings.HasPrefix(value, "{{") || !strings.HasSuffix(value, "}}") { |
| 4115 | woc.reportMetricEmissionError(ctx, "real time metrics can only be used with metric variables") |
| 4116 | continue |
| 4117 | } |
| 4118 | value = strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(value, "{{"), "}}")) |
| 4119 | valueFunc, ok := realTimeScope[value] |
| 4120 | if !ok { |
no test coverage detected