Add rusage-logfile flag to optionally send rusage to a file

Currently the rusage is reported to stdout and rather cumbersome to parse. The
new flag rusage-logfile can be used to specify a file to which the log will be
written instead.

Signed-off-by: Dan Čermák <dcermak@suse.com>
This commit is contained in:
Dan Čermák 2021-05-28 17:09:27 +02:00
parent 4fa566ead2
commit a6b3b6f672
No known key found for this signature in database
GPG Key ID: 8F8C178E966641D3
6 changed files with 44 additions and 3 deletions

View File

@ -334,6 +334,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error {
Isolation: isolation,
Labels: iopts.Label,
Layers: layers,
LogRusage: iopts.LogRusage,
Manifest: iopts.Manifest,
MaxPullPushRetries: maxPullPushRetries,
NamespaceOptions: namespaceOptions,
@ -349,6 +350,7 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error {
ReportWriter: reporter,
Runtime: iopts.Runtime,
RuntimeArgs: runtimeFlags,
RusageLogFile: iopts.RusageLogFile,
SignBy: iopts.SignBy,
SignaturePolicyPath: iopts.SignaturePolicy,
Squash: iopts.Squash,
@ -357,7 +359,6 @@ func budCmd(c *cobra.Command, inputArgs []string, iopts budOptions) error {
TransientMounts: iopts.Volumes,
OciDecryptConfig: decConfig,
Jobs: &iopts.Jobs,
LogRusage: iopts.LogRusage,
}
if iopts.IgnoreFile != "" {
excludes, err := parseDockerignore(iopts.IgnoreFile)

View File

@ -217,6 +217,8 @@ type BuildOptions struct {
Jobs *int
// LogRusage logs resource usage for each step.
LogRusage bool
// File to which the Rusage logs will be saved to instead of stdout
RusageLogFile string
// Excludes is a list of excludes to be used instead of the .dockerignore file.
Excludes []string
// From is the image name to use to replace the value specified in the first

View File

@ -116,6 +116,7 @@ type Executor struct {
stagesSemaphore *semaphore.Weighted
jobs int
logRusage bool
rusageLogFile *os.File
imageInfoLock sync.Mutex
imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs
fromOverride string
@ -183,6 +184,18 @@ func NewExecutor(logger *logrus.Logger, store storage.Store, options define.Buil
writer = ioutil.Discard
}
var rusageLogFile *os.File
if options.LogRusage && !options.Quiet {
if options.RusageLogFile == "" {
rusageLogFile = os.Stdout
} else {
rusageLogFile, err = os.OpenFile(options.RusageLogFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
}
}
exec := Executor{
logger: logger,
stages: make(map[string]*StageExecutor),
@ -241,6 +254,7 @@ func NewExecutor(logger *logrus.Logger, store storage.Store, options define.Buil
terminatedStage: make(map[string]struct{}),
jobs: jobs,
logRusage: options.LogRusage,
rusageLogFile: rusageLogFile,
imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs),
fromOverride: options.From,
manifest: options.Manifest,
@ -530,6 +544,12 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
}
}
cleanupImages = nil
if b.rusageLogFile != nil && b.rusageLogFile != os.Stdout {
// we deliberately ignore the error here, as this
// function can be called multiple times
b.rusageLogFile.Close()
}
return lastErr
}

View File

@ -704,8 +704,8 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
fmt.Fprintf(s.executor.out, "error gathering resource usage information: %v\n", err)
return
}
if !s.executor.quiet && s.executor.logRusage {
fmt.Fprintf(s.executor.out, "%s\n", rusage.FormatDiff(usage.Subtract(resourceUsage)))
if s.executor.rusageLogFile != nil {
fmt.Fprintf(s.executor.rusageLogFile, "%s\n", rusage.FormatDiff(usage.Subtract(resourceUsage)))
}
resourceUsage = usage
}

View File

@ -84,6 +84,7 @@ type BudResults struct {
TLSVerify bool
Jobs int
LogRusage bool
RusageLogFile string
}
// FromAndBugResults represents the results for common flags
@ -199,6 +200,10 @@ func GetBudFlags(flags *BudResults) pflag.FlagSet {
if err := fs.MarkHidden("log-rusage"); err != nil {
panic(fmt.Sprintf("error marking the log-rusage flag as hidden: %v", err))
}
fs.StringVar(&flags.RusageLogFile, "rusage-logfile", "", "destination file to which rusage should be logged to instead of stdout (= the default).")
if err := fs.MarkHidden("rusage-logfile"); err != nil {
panic(fmt.Sprintf("error marking the rusage-logfile flag as hidden: %v", err))
}
fs.StringVar(&flags.Manifest, "manifest", "", "add the image to the specified manifest list. Creates manifest if it does not exist")
fs.BoolVar(&flags.NoCache, "no-cache", false, "Do not use existing cached images for the container build. Build from the start with a new set of cached layers.")
fs.String("os", runtime.GOOS, "set the OS to the provided value instead of the current operating system of the host")

View File

@ -2423,6 +2423,19 @@ EOM
expect_output --substring ".*\(system\).*\(user\).*\(elapsed\).*input.*output"
}
@test "bud with-rusage-logfile" {
_prefetch alpine
run_buildah bud --log-rusage --rusage-logfile "foo.log" --layers --pull=false --format docker --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/shell
# the logfile should exist
if [ ! -e "foo.log" ]; then die "foo.log not present!"; fi
# expect that foo.log only contains lines that were formatted using pkg/rusage.FormatDiff()
formatted_lines=$(grep ".*\(system\).*\(user\).*\(elapsed\).*input.*output" foo.log | wc -l)
line_count=$(cat foo.log | wc -l)
if [[ "$formatted_lines" -ne "$line_count" ]]; then
die "Got ${formatted_lines} lines formatted with pkg/rusage.FormatDiff() but foo.log has ${line_count} lines"
fi
}
@test "bud-caching-from-scratch" {
_prefetch alpine
# run the build once