-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(metrics-operator): expose analysis results as Prometheus Metric (#…
…2137) Signed-off-by: Giovanni Liva <giovanni.liva@dynatrace.com> Signed-off-by: Florian Bacher <florian.bacher@dynatrace.com> Co-authored-by: Giovanni Liva <giovanni.liva@dynatrace.com>
- Loading branch information
Showing
12 changed files
with
339 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package analysis | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"sync" | ||
|
||
analysistypes "github.com/keptn/lifecycle-toolkit/metrics-operator/controllers/common/analysis/types" | ||
"github.com/prometheus/client_golang/prometheus" | ||
"k8s.io/klog/v2" | ||
) | ||
|
||
const analysisResultMetricName = "keptn_analysis_result" | ||
const objectiveResultMetricName = "keptn_objective_result" | ||
|
||
type Metrics struct { | ||
AnalysisResult *prometheus.GaugeVec | ||
ObjectiveResult *prometheus.GaugeVec | ||
} | ||
|
||
// use singleton pattern here to avoid registering the same metrics on Prometheus multiple times | ||
var instance *resultsReporter | ||
var once sync.Once | ||
|
||
func GetResultsReporter(ctx context.Context, res chan analysistypes.AnalysisCompletion) *resultsReporter { | ||
once.Do(func() { | ||
instance = &resultsReporter{} | ||
instance.initialize(ctx, res) | ||
}) | ||
|
||
return instance | ||
} | ||
|
||
type resultsReporter struct { | ||
metrics Metrics | ||
mtx sync.Mutex | ||
} | ||
|
||
func (r *resultsReporter) initialize(ctx context.Context, res chan analysistypes.AnalysisCompletion) { | ||
labelNamesAnalysis := []string{"name", "namespace", "from", "to"} | ||
a := prometheus.NewGaugeVec(prometheus.GaugeOpts{ | ||
Name: analysisResultMetricName, | ||
Help: "Result of Analysis", | ||
}, labelNamesAnalysis) | ||
err := prometheus.Register(a) | ||
|
||
if err != nil { | ||
klog.Errorf("Could not register Analysis results as Prometheus metric: %v", err) | ||
} | ||
|
||
labelNames := []string{"name", "namespace", "analysis_name", "analysis_namespace", "key_objective", "weight", "from", "to"} | ||
o := prometheus.NewGaugeVec(prometheus.GaugeOpts{ | ||
Name: objectiveResultMetricName, | ||
Help: "Result of the Analysis Objective", | ||
}, labelNames) | ||
err = prometheus.Register(o) | ||
if err != nil { | ||
klog.Errorf("Could not register Analysis Objective results as Prometheus metric: %v", err) | ||
} | ||
|
||
r.metrics = Metrics{ | ||
AnalysisResult: a, | ||
ObjectiveResult: o, | ||
} | ||
|
||
go r.watchForResults(ctx, res) | ||
} | ||
|
||
func (r *resultsReporter) watchForResults(ctx context.Context, res chan analysistypes.AnalysisCompletion) { | ||
for { | ||
select { | ||
case <-ctx.Done(): | ||
klog.Info("Exiting due to termination of context") | ||
return | ||
case finishedAnalysis := <-res: | ||
r.reportResult(finishedAnalysis) | ||
} | ||
} | ||
} | ||
|
||
func (r *resultsReporter) reportResult(finishedAnalysis analysistypes.AnalysisCompletion) { | ||
r.mtx.Lock() | ||
defer r.mtx.Unlock() | ||
|
||
f := finishedAnalysis.Analysis.Spec.From.String() | ||
t := finishedAnalysis.Analysis.Spec.To.String() | ||
labelsAnalysis := prometheus.Labels{ | ||
"name": finishedAnalysis.Analysis.Name, | ||
"namespace": finishedAnalysis.Analysis.Namespace, | ||
"from": f, | ||
"to": t, | ||
} | ||
if m, err := r.metrics.AnalysisResult.GetMetricWith(labelsAnalysis); err == nil { | ||
m.Set(finishedAnalysis.Result.GetAchievedPercentage()) | ||
} else { | ||
klog.Errorf("unable to set value for analysis result metric: %v", err) | ||
} | ||
// expose also the individual objectives | ||
for _, o := range finishedAnalysis.Result.ObjectiveResults { | ||
name := o.Objective.AnalysisValueTemplateRef.Name | ||
ns := o.Objective.AnalysisValueTemplateRef.Namespace | ||
labelsObjective := prometheus.Labels{ | ||
"name": name, | ||
"namespace": ns, | ||
"analysis_name": finishedAnalysis.Analysis.Name, | ||
"analysis_namespace": finishedAnalysis.Analysis.Namespace, | ||
"key_objective": fmt.Sprintf("%v", o.Objective.KeyObjective), | ||
"weight": fmt.Sprintf("%v", o.Objective.Weight), | ||
"from": f, | ||
"to": t, | ||
} | ||
if m, err := r.metrics.ObjectiveResult.GetMetricWith(labelsObjective); err == nil { | ||
m.Set(o.Value) | ||
} else { | ||
klog.Errorf("unable to set value for objective result metric: %v", err) | ||
} | ||
} | ||
} |
Oops, something went wrong.