package app import ( "context" "fmt" "io" "os" "sync" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/service" "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" ) var logOpts = types.ContainerLogsOptions{ Details: false, Follow: true, ShowStderr: true, ShowStdout: true, Tail: "20", Timestamps: true, } // stackLogs lists logs for all stack services func stackLogs(c *cli.Context, app config.App, client *dockerClient.Client) { filters, err := app.Filters(true, false) if err != nil { logrus.Fatal(err) } serviceOpts := types.ServiceListOptions{Filters: filters} services, err := client.ServiceList(context.Background(), serviceOpts) if err != nil { logrus.Fatal(err) } var wg sync.WaitGroup for _, service := range services { wg.Add(1) go func(s string) { if internal.StdErrOnly { logOpts.ShowStdout = false } logs, err := client.ServiceLogs(context.Background(), s, logOpts) if err != nil { logrus.Fatal(err) } 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", Flags: []cli.Flag{ internal.StdErrOnlyFlag, internal.DebugFlag, }, Before: internal.SubCommandBefore, 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) } serviceName := c.Args().Get(1) if serviceName == "" { logrus.Debugf("tailing logs for all %s services", app.Recipe) stackLogs(c, app, cl) } else { logrus.Debugf("tailing logs for %s", serviceName) if err := tailServiceLogs(c, cl, app, serviceName); err != nil { logrus.Fatal(err) } } return nil }, } func tailServiceLogs(c *cli.Context, cl *dockerClient.Client, app config.App, serviceName string) error { filters := filters.NewArgs() filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), serviceName)) chosenService, err := service.GetService(context.Background(), cl, filters, internal.NoInput) if err != nil { logrus.Fatal(err) } if internal.StdErrOnly { logOpts.ShowStdout = false } logs, err := cl.ServiceLogs(context.Background(), chosenService.ID, logOpts) if err != nil { logrus.Fatal(err) } defer logs.Close() _, err = io.Copy(os.Stdout, logs) if err != nil && err != io.EOF { logrus.Fatal(err) } return nil }