Skip to content

Commit

Permalink
fix: logs for tasks (#2499)
Browse files Browse the repository at this point in the history
## Description
This PR manipulates `run_sh` and `run_python` logic to stream logs from
the command or python script thats being executed on the container. This
also allows retrieving task logs after a run has finished, whereas
before, task containers would not return logs from `kurtosis service
logs`.

An improvement to this would be to enable streaming back logs via run
output so users don't have to go through Docker Desktop or docker cli to
view logs from a long running task that might have err'd.

https://www.loom.com/share/89181c37442048b9bdc746bfd37fe2ec

## Is this change user facing?
YES
  • Loading branch information
tedim52 authored Jul 3, 2024
1 parent 713e7dd commit e7ef915
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func (builtin *RunPythonCapabilities) Execute(ctx context.Context, _ *builtin_ar
if err != nil {
return "", stacktrace.Propagate(err, "error occurred while preparing the sh command to execute on the image")
}
fullCommandToRun := []string{shellWrapperCommand, "-c", commandToRun}
fullCommandToRun := getCommandToRunForStreamingLogs(commandToRun)

// run the command passed in by user in the container
runPythonExecutionResult, err := executeWithWait(ctx, builtin.serviceNetwork, builtin.name, builtin.wait, fullCommandToRun)
Expand Down Expand Up @@ -418,7 +418,7 @@ func getPythonCommandToRun(builtin *RunPythonCapabilities) (string, error) {
argumentsAsString := strings.Join(maybePythonArgumentsWithRuntimeValueReplaced, spaceDelimiter)
runEscaped := strings.ReplaceAll(builtin.run, `"`, `\"`)
if len(argumentsAsString) > 0 {
return fmt.Sprintf(`python -c "%s" %s`, runEscaped, argumentsAsString), nil
return fmt.Sprintf(`python -u -c "%s" %s`, runEscaped, argumentsAsString), nil
}
return fmt.Sprintf(`python -c "%s"`, runEscaped), nil
return fmt.Sprintf(`python -u -c "%s"`, runEscaped), nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func (builtin *RunShCapabilities) Execute(ctx context.Context, _ *builtin_argume
if err != nil {
return "", stacktrace.Propagate(err, "error occurred while preparing the sh command to execute on the image")
}
fullCommandToRun := []string{shellWrapperCommand, "-c", commandToRun}
fullCommandToRun := getCommandToRunForStreamingLogs(commandToRun)

// run the command passed in by user in the container
createDefaultDirectoryResult, err := executeWithWait(ctx, builtin.serviceNetwork, builtin.name, builtin.wait, fullCommandToRun)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,24 @@ const (
runFilesArtifactsKey = "files_artifacts"

shellWrapperCommand = "/bin/sh"
taskLogFilePath = "/tmp/kurtosis-task.log"
noNameSet = ""
uniqueNameGenErrStr = "error occurred while generating unique name for the file artifact"

// enables init mode on containers; cleaning up any zombie processes
tiniEnabled = true
)

var runTailCommandToPreventContainerToStopOnCreating = []string{"tail", "-f", "/dev/null"}
var runCommandToStreamTaskLogs = []string{shellWrapperCommand, "-c", fmt.Sprintf("touch %s && tail -F %s", taskLogFilePath, taskLogFilePath)}

// Wraps [commandToRun] to enable streaming logs from tasks.
// Uses curly braces to execute the command(s) in the current shell.
// Adds an extra echo to ensure each log ends with a newline.
// Uses tee to direct output to the task log file while maintaining output to stdout.
// Redirects stderr to stdout.
func getCommandToRunForStreamingLogs(commandToRun string) []string {
return []string{shellWrapperCommand, "-c", fmt.Sprintf("{ %v; } %v %v %v %v %v %v %v %v", commandToRun, "2>&1", "|", "tee", taskLogFilePath, "&&", "echo", ">>", taskLogFilePath)}
}

func parseStoreFilesArg(serviceNetwork service_network.ServiceNetwork, arguments *builtin_argument.ArgumentValuesSet) ([]*store_spec.StoreSpec, *startosis_errors.InterpretationError) {
var result []*store_spec.StoreSpec
Expand Down Expand Up @@ -276,7 +286,7 @@ func getServiceConfig(
filesArtifactExpansion *service_directory.FilesArtifactsExpansion,
envVars *map[string]string,
) (*service.ServiceConfig, error) {
serviceConfig, err := service.CreateServiceConfig(maybeImageName, maybeImageBuildSpec, maybeImageRegistrySpec, maybeNixBuildSpec, nil, nil, runTailCommandToPreventContainerToStopOnCreating, nil, *envVars, filesArtifactExpansion, nil, 0, 0, service_config.DefaultPrivateIPAddrPlaceholder, 0, 0, map[string]string{}, nil, nil, map[string]string{}, image_download_mode.ImageDownloadMode_Missing, tiniEnabled)
serviceConfig, err := service.CreateServiceConfig(maybeImageName, maybeImageBuildSpec, maybeImageRegistrySpec, maybeNixBuildSpec, nil, nil, runCommandToStreamTaskLogs, nil, *envVars, filesArtifactExpansion, nil, 0, 0, service_config.DefaultPrivateIPAddrPlaceholder, 0, 0, map[string]string{}, nil, nil, map[string]string{}, image_download_mode.ImageDownloadMode_Missing, tiniEnabled)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred creating service config")
}
Expand Down

0 comments on commit e7ef915

Please sign in to comment.