func()

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
	}
}