in pkg/gcpbuildpack/builderoutput.go [149:236]
func (ctx *Context) saveSuccessOutput(duration time.Duration) {
outputDir := os.Getenv(builderOutputEnv)
if outputDir == "" {
return
}
bo := builderoutput.New()
fname := filepath.Join(outputDir, builderOutputFilename)
fnameExists, err := ctx.FileExists(fname)
if err != nil {
ctx.Warnf("Failed to determine if %s exists, skipping statistics: %v", fname, err)
return
}
// Previous buildpacks may have already written to the builder output file.
if fnameExists {
content, err := ioutil.ReadFile(fname)
if err != nil {
ctx.Warnf("Failed to read %s, skipping statistics: %v", fname, err)
return
}
bofj, err := builderoutput.FromJSON(content)
bo = &bofj
if err != nil {
ctx.Warnf("Failed to unmarshal %s, skipping statistics: %v", fname, err)
return
}
}
if len(ctx.InstalledRuntimeVersions()) > 0 {
bo.InstalledRuntimeVersions = append(bo.InstalledRuntimeVersions, ctx.InstalledRuntimeVersions()...)
}
bo.Stats = append(bo.Stats, builderoutput.BuilderStat{
BuildpackID: ctx.BuildpackID(),
BuildpackVersion: ctx.BuildpackVersion(),
DurationMs: duration.Milliseconds(),
UserDurationMs: ctx.stats.user.Milliseconds(),
})
bo.Warnings = append(bo.Warnings, ctx.warnings...)
bm := buildermetrics.GlobalBuilderMetrics()
bm.ForEachCounter(func(id buildermetrics.MetricID, c *buildermetrics.Counter) {
count := bo.Metrics.GetCounter(id)
count.Increment(c.Value())
})
bmd := buildermetadata.GlobalBuilderMetadata()
bmd.ForEachValue(func(id buildermetadata.MetadataID, m buildermetadata.MetadataValue) {
(&bo.Metadata).SetValue(id, m)
})
var content []byte
// Make sure the message is smaller than the maximum allowed size.
for {
var err error
content, err = bo.JSON()
if err != nil {
ctx.Warnf("Failed to marshal stats, skipping statistics: %v", err)
return
}
if len(content) <= maxMessageBytes {
break
}
// This is a defensive check; if there are no warnings, the message should be small enough.
// In either case, skip this stat.
if len(bo.Warnings) == 0 {
ctx.Warnf("The builder output is too large and there are no warnings, skipping statistics")
return
}
diff := len(content) - maxMessageBytes
last := len(bo.Warnings) - 1
// If the last warning is too long, only trim it. Otherwise, drop it.
// Also drop the last warning if it is shorter than three characters.
if len(bo.Warnings[last]) > diff+3 {
bo.Warnings[last] = bo.Warnings[last][:len(bo.Warnings[last])-diff-3] + "..."
} else {
bo.Warnings = bo.Warnings[:last]
}
}
if err := os.MkdirAll(outputDir, 0755); err != nil {
ctx.Warnf("Failed to create dir %s, skipping statistics: %v", outputDir, err)
return
}
if err := ioutil.WriteFile(fname, content, 0644); err != nil {
ctx.Warnf("Failed to write %s, skipping statistics: %v", fname, err)
return
}
}