metricwriter: compile regular expressions only on first use

Compile the regular expressions only on first use rather than implicitly
as part of the `init()` function of the package. This prevents taking a
speed hit on the initialization of the package regardless if this type
is used and moves it to the time when a regular expression is first
used.

Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
This commit is contained in:
Jonathan A. Sternberg 2024-08-05 10:23:06 -05:00
parent e2f6808457
commit 2810f20f3a
No known key found for this signature in database
GPG Key ID: 6603D4B96394F6B1
1 changed files with 33 additions and 25 deletions

View File

@ -17,6 +17,31 @@ import (
"golang.org/x/text/language"
)
type rePatterns struct {
LocalSourceType *regexp.Regexp
ImageSourceType *regexp.Regexp
ExecType *regexp.Regexp
ExportImageType *regexp.Regexp
LintMessage *regexp.Regexp
}
var re = sync.OnceValue(func() *rePatterns {
return &rePatterns{
LocalSourceType: regexp.MustCompile(
strings.Join([]string{
`(?P<context>\[internal] load build context)`,
`(?P<dockerfile>load build definition)`,
`(?P<dockerignore>load \.dockerignore)`,
`(?P<namedcontext>\[context .+] load from client)`,
}, "|"),
),
ImageSourceType: regexp.MustCompile(`^\[.*] FROM `),
ExecType: regexp.MustCompile(`^\[.*] RUN `),
ExportImageType: regexp.MustCompile(`^exporting to (image|(?P<format>\w+) image format)$`),
LintMessage: regexp.MustCompile(`^https://docs\.docker\.com/go/dockerfile/rule/([\w|-]+)/`),
}
})
type metricWriter struct {
recorders []metricRecorder
attrs attribute.Set
@ -128,22 +153,13 @@ func (mr *localSourceTransferMetricRecorder) Record(ss *client.SolveStatus) {
}
}
var reLocalSourceType = regexp.MustCompile(
strings.Join([]string{
`(?P<context>\[internal] load build context)`,
`(?P<dockerfile>load build definition)`,
`(?P<dockerignore>load \.dockerignore)`,
`(?P<namedcontext>\[context .+] load from client)`,
}, "|"),
)
func detectLocalSourceType(vertexName string) attribute.KeyValue {
match := reLocalSourceType.FindStringSubmatch(vertexName)
match := re().LocalSourceType.FindStringSubmatch(vertexName)
if match == nil {
return attribute.KeyValue{}
}
for i, source := range reLocalSourceType.SubexpNames() {
for i, source := range re().LocalSourceType.SubexpNames() {
if len(source) == 0 {
// Not a subexpression.
continue
@ -241,10 +257,8 @@ func (mr *imageSourceMetricRecorder) Record(ss *client.SolveStatus) {
}
}
var reImageSourceType = regexp.MustCompile(`^\[.*] FROM `)
func detectImageSourceType(vertexName string) bool {
return reImageSourceType.MatchString(vertexName)
return re().ImageSourceType.MatchString(vertexName)
}
type (
@ -278,10 +292,8 @@ func (mr *execMetricRecorder) Record(ss *client.SolveStatus) {
}
}
var reExecType = regexp.MustCompile(`^\[.*] RUN `)
func detectExecType(vertexName string) bool {
return reExecType.MatchString(vertexName)
return re().ExecType.MatchString(vertexName)
}
type (
@ -325,10 +337,8 @@ func (mr *exportImageMetricRecorder) Record(ss *client.SolveStatus) {
}
}
var reExportImageType = regexp.MustCompile(`^exporting to (image|(?P<format>\w+) image format)$`)
func detectExportImageType(vertexName string) string {
m := reExportImageType.FindStringSubmatch(vertexName)
m := re().ExportImageType.FindStringSubmatch(vertexName)
if m == nil {
return ""
}
@ -456,7 +466,10 @@ func kebabToCamel(s string) string {
return strings.Join(words, "")
}
var lintRuleNameProperty = attribute.Key("lint.rule.name")
func (mr *lintMetricRecorder) Record(ss *client.SolveStatus) {
reLintMessage := re().LintMessage
for _, warning := range ss.Warnings {
m := reLintMessage.FindSubmatch([]byte(warning.URL))
if len(m) < 2 {
@ -472,8 +485,3 @@ func (mr *lintMetricRecorder) Record(ss *client.SolveStatus) {
)
}
}
var (
reLintMessage = regexp.MustCompile(`^https://docs\.docker\.com/go/dockerfile/rule/([\w|-]+)/`)
lintRuleNameProperty = attribute.Key("lint.rule.name")
)