diff --git a/cli/app/logs.go b/cli/app/logs.go index 04dfed5f..1eff8335 100644 --- a/cli/app/logs.go +++ b/cli/app/logs.go @@ -9,6 +9,7 @@ import ( "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" + "coopcloud.tech/abra/pkg/config" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" @@ -16,6 +17,15 @@ import ( "github.com/urfave/cli/v2" ) +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, stackName string, client *dockerClient.Client) { filters := filters.NewArgs() @@ -30,14 +40,10 @@ func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) { 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, + if internal.StdErrOnly { + logOpts.ShowStdout = false } + logs, err := client.ServiceLogs(c.Context, s, logOpts) if err != nil { logrus.Fatal(err) @@ -60,6 +66,10 @@ var appLogsCommand = &cli.Command{ Aliases: []string{"l"}, ArgsUsage: "[]", Usage: "Tail app logs", + Flags: []cli.Flag{ + internal.StdErrOnlyFlag, + }, + BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) @@ -70,44 +80,47 @@ var appLogsCommand = &cli.Command{ serviceName := c.Args().Get(1) if serviceName == "" { - logrus.Debug("tailing logs for all app services") + logrus.Debugf("tailing logs for all %s services", app.Type) 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) + } else { + logrus.Debugf("tailing logs for %s", serviceName) + if err := tailServiceLogs; err != nil { + logrus.Fatal(err) + } } return nil }, - BashComplete: autocomplete.AppNameComplete, +} + +func tailServiceLogs(c *cli.Context, cl *dockerClient.Client, app config.App, serviceName string) error { + 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)) + } + + if internal.StdErrOnly { + logOpts.ShowStdout = false + } + + 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 } diff --git a/cli/internal/common.go b/cli/internal/common.go index dd786993..26480110 100644 --- a/cli/internal/common.go +++ b/cli/internal/common.go @@ -401,6 +401,15 @@ var NoDomainChecksFlag = &cli.BoolFlag{ Destination: &NoDomainChecks, } +var StdErrOnly bool +var StdErrOnlyFlag = &cli.BoolFlag{ + Name: "stderr", + Aliases: []string{"s"}, + Value: false, + Usage: "Only tail stderr", + Destination: &StdErrOnly, +} + // SSHFailMsg is a hopefully helpful SSH failure message var SSHFailMsg = ` Woops, Abra is unable to connect to connect to %s.