package app import ( "fmt" "io" "os" "sync" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) // stackLogs lists logs for all stack services func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) { filters := filters.NewArgs() filters.Add("name", stackName) serviceOpts := types.ServiceListOptions{Filters: filters} services, err := client.ServiceList(c.Context, serviceOpts) if err != nil { logrus.Fatal(err) } var wg sync.WaitGroup for _, service := range services { wg.Add(1) go func(s string) { logOpts := types.ContainerLogsOptions{ Details: false, Follow: true, ShowStderr: true, ShowStdout: true, Tail: "20", Timestamps: true, } logs, err := client.ServiceLogs(c.Context, s, logOpts) if err != nil { logrus.Fatal(err) } // defer after err check as any err returns a nil io.ReadCloser defer logs.Close() _, err = io.Copy(os.Stdout, logs) if err != nil && err != io.EOF { logrus.Fatal(err) } }(service.ID) } wg.Wait() os.Exit(0) } var appLogsCommand = &cli.Command{ Name: "logs", Aliases: []string{"l"}, ArgsUsage: "[]", Usage: "Tail app logs", Action: func(c *cli.Context) error { app := internal.ValidateApp(c) cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } serviceName := c.Args().Get(1) if serviceName == "" { logrus.Debug("tailing logs for all app services") stackLogs(c, app.StackName(), cl) } logrus.Debugf("tailing logs for '%s'", serviceName) service := fmt.Sprintf("%s_%s", app.StackName(), serviceName) filters := filters.NewArgs() filters.Add("name", service) serviceOpts := types.ServiceListOptions{Filters: filters} services, err := cl.ServiceList(c.Context, serviceOpts) if err != nil { logrus.Fatal(err) } if len(services) != 1 { logrus.Fatalf("expected 1 service but got %v", len(services)) } logOpts := types.ContainerLogsOptions{ Details: false, Follow: true, ShowStderr: true, ShowStdout: true, Tail: "20", Timestamps: true, } logs, err := cl.ServiceLogs(c.Context, services[0].ID, logOpts) if err != nil { logrus.Fatal(err) } // defer after err check as any err returns a nil io.ReadCloser defer logs.Close() _, err = io.Copy(os.Stdout, logs) if err != nil && err != io.EOF { logrus.Fatal(err) } return nil }, BashComplete: autocomplete.AppNameComplete, }