package app import ( "strconv" "strings" abraFormatter "coopcloud.tech/abra/cli/formatter" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" stack "coopcloud.tech/abra/pkg/upstream/stack" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) var appErrorsCommand = &cli.Command{ Name: "errors", Usage: "List errors for a deployed app", Description: ` This command will list errors for a deployed app. This is a best-effort implementation and an attempt to gather a number of tips & tricks for finding errors together into one convenient command. When an app is failing to deploy or having issues, it could be a lot of things. This command is best accompanied by "abra app logs ". `, Aliases: []string{"e"}, Flags: []cli.Flag{}, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } isDeployed, _, err := stack.IsDeployed(c.Context, cl, app.StackName()) if err != nil { logrus.Fatal(err) } if !isDeployed { logrus.Fatalf("%s is not deployed?", app.Name) } filters := filters.NewArgs() filters.Add("name", app.StackName()) containers, err := cl.ContainerList(c.Context, types.ContainerListOptions{Filters: filters}) if err != nil { logrus.Fatal(err) } tableCol := []string{"app name", "status", "error", "out of memory", "restart count", "healthcheck"} table := abraFormatter.CreateTable(tableCol) for _, container := range containers { serviceName := getServiceName(container.Names) containerState, err := cl.ContainerInspect(c.Context, container.ID) if err != nil { logrus.Fatal(err) } errMsg := "N/A" hcStat := "N/A" var hcLogs []string if containerState.State.Health != nil { hcStat = containerState.State.Health.Status for _, log := range containerState.State.Health.Log { hcLogs = append(hcLogs, log.Output) } } if containerState.State.Error != "" { errMsg = containerState.State.Error } table.Append([]string{ serviceName, containerState.State.Status, errMsg, strconv.FormatBool(containerState.State.OOMKilled), strconv.Itoa(containerState.RestartCount), hcStat, strings.Join(hcLogs, "\n"), }) } table.Render() return nil }, } func getServiceName(names []string) string { containerName := strings.Join(names, " ") trimmed := strings.TrimPrefix(containerName, "/") return strings.Split(trimmed, ".")[0] }