From 1a93bbd3a51a949a8db8b169a716bab1e525be0e Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Wed, 29 May 2024 14:01:52 -0500 Subject: [PATCH] metrics: record the number of times lint rules are triggered during a build This metric records the number of times it sees a lint warning in the progress stream and categorizes the number of times each rule has been triggered. This will only record whether a lint warning was triggered and not whether the linter was even used or which rules were present. That information isn't presently part of the stream. With this change, we might be reaching some of the limitations that spying on the progress stream gives us for metrics and may want to consider another way for the build to communicate metrics back to the client. Signed-off-by: Jonathan A. Sternberg --- util/progress/metricwriter.go | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/util/progress/metricwriter.go b/util/progress/metricwriter.go index e4491b53..5173b8b9 100644 --- a/util/progress/metricwriter.go +++ b/util/progress/metricwriter.go @@ -29,6 +29,7 @@ func newMetrics(mp metric.MeterProvider, attrs attribute.Set) *metricWriter { newExecMetricRecorder(meter, attrs), newExportImageMetricRecorder(meter, attrs), newIdleMetricRecorder(meter, attrs), + newLintMetricRecorder(meter, attrs), }, attrs: attrs, } @@ -426,3 +427,43 @@ func calculateIdleTime(started, completed []time.Time) time.Duration { } return elapsed } + +type lintMetricRecorder struct { + // Attributes holds the set of attributes for all metrics produced. + Attributes attribute.Set + + // Count holds the metric for the number of times a lint rule has been triggered + // within the current build. + Count metric.Int64Counter +} + +func newLintMetricRecorder(meter metric.Meter, attrs attribute.Set) *lintMetricRecorder { + mr := &lintMetricRecorder{ + Attributes: attrs, + } + mr.Count, _ = meter.Int64Counter("lint.trigger.count", + metric.WithDescription("Measures the number of times a lint rule has been triggered.")) + return mr +} + +func (mr *lintMetricRecorder) Record(ss *client.SolveStatus) { + for _, warning := range ss.Warnings { + m := reLintMessage.FindSubmatch(warning.Short) + if m == nil { + continue + } + + ruleName := string(m[1]) + mr.Count.Add(context.Background(), 1, + metric.WithAttributeSet(mr.Attributes), + metric.WithAttributes( + lintRuleNameProperty.String(ruleName), + ), + ) + } +} + +var ( + reLintMessage = regexp.MustCompile(`^Lint Rule '(\w+)':`) + lintRuleNameProperty = attribute.Key("lint.rule.name") +)