From 056dfb95bc1a9bea75bfaf7c16c15db3e4622abb Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 16 Dec 2020 16:58:54 +0100 Subject: [PATCH] allow to collect logs for a subset of project services Signed-off-by: Nicolas De Loof --- aci/compose.go | 2 +- api/client/compose.go | 2 +- api/compose/api.go | 7 ++++++- cli/cmd/compose/logs.go | 12 +++++++----- ecs/local/compose.go | 2 +- ecs/logs.go | 30 +++++++++++++++++++++++++++++- example/backend.go | 2 +- local/compose/logs.go | 15 ++++++++++++++- 8 files changed, 60 insertions(+), 12 deletions(-) diff --git a/aci/compose.go b/aci/compose.go index 03bbbb895..2b9f47b4b 100644 --- a/aci/compose.go +++ b/aci/compose.go @@ -194,7 +194,7 @@ func (cs *aciComposeService) List(ctx context.Context, project string) ([]compos return stacks, nil } -func (cs *aciComposeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer) error { +func (cs *aciComposeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { return errdefs.ErrNotImplemented } diff --git a/api/client/compose.go b/api/client/compose.go index e139e20f2..b069a6ab4 100644 --- a/api/client/compose.go +++ b/api/client/compose.go @@ -56,7 +56,7 @@ func (c *composeService) Down(context.Context, string) error { return errdefs.ErrNotImplemented } -func (c *composeService) Logs(context.Context, string, compose.LogConsumer) error { +func (c *composeService) Logs(context.Context, string, compose.LogConsumer, compose.LogOptions) error { return errdefs.ErrNotImplemented } diff --git a/api/compose/api.go b/api/compose/api.go index e1badf3da..1a2b6f234 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -39,7 +39,7 @@ type Service interface { // Down executes the equivalent to a `compose down` Down(ctx context.Context, projectName string) error // Logs executes the equivalent to a `compose logs` - Logs(ctx context.Context, projectName string, consumer LogConsumer) error + Logs(ctx context.Context, projectName string, consumer LogConsumer, options LogOptions) error // Ps executes the equivalent to a `compose ps` Ps(ctx context.Context, projectName string) ([]ContainerSummary, error) // List executes the equivalent to a `docker stack ls` @@ -76,6 +76,11 @@ type ServiceStatus struct { Publishers []PortPublisher } +// LogOptions defines optional parameters for the `Log` API +type LogOptions struct { + Services []string +} + const ( // STARTING indicates that stack is being deployed STARTING string = "Starting" diff --git a/cli/cmd/compose/logs.go b/cli/cmd/compose/logs.go index 127642994..e75b0bdb2 100644 --- a/cli/cmd/compose/logs.go +++ b/cli/cmd/compose/logs.go @@ -21,18 +21,18 @@ import ( "os" "github.com/docker/compose-cli/api/client" + "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/formatter" - "github.com/spf13/cobra" ) func logsCommand() *cobra.Command { opts := composeOptions{} logsCmd := &cobra.Command{ - Use: "logs", + Use: "logs [service...]", Short: "View output from containers", RunE: func(cmd *cobra.Command, args []string) error { - return runLogs(cmd.Context(), opts) + return runLogs(cmd.Context(), opts, args) }, } logsCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name") @@ -42,7 +42,7 @@ func logsCommand() *cobra.Command { return logsCmd } -func runLogs(ctx context.Context, opts composeOptions) error { +func runLogs(ctx context.Context, opts composeOptions, services []string) error { c, err := client.NewWithDefaultLocalBackend(ctx) if err != nil { return err @@ -53,5 +53,7 @@ func runLogs(ctx context.Context, opts composeOptions) error { return err } consumer := formatter.NewLogConsumer(ctx, os.Stdout) - return c.ComposeService().Logs(ctx, projectName, consumer) + return c.ComposeService().Logs(ctx, projectName, consumer, compose.LogOptions{ + Services: services, + }) } diff --git a/ecs/local/compose.go b/ecs/local/compose.go index 9bf64a5f9..abe9812d5 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -180,7 +180,7 @@ services: return cmd.Run() } -func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer) error { +func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { list, err := e.moby.ContainerList(ctx, types2.ContainerListOptions{ Filters: filters.NewArgs(filters.Arg("label", "com.docker.compose.project="+projectName)), }) diff --git a/ecs/logs.go b/ecs/logs.go index fd991e961..2be5b6708 100644 --- a/ecs/logs.go +++ b/ecs/logs.go @@ -22,7 +22,35 @@ import ( "github.com/docker/compose-cli/api/compose" ) -func (b *ecsAPIService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer) error { +func (b *ecsAPIService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { + if len(options.Services) > 0 { + consumer = filteredLogConsumer(consumer, options.Services) + } err := b.aws.GetLogs(ctx, projectName, consumer.Log) return err } + +func filteredLogConsumer(consumer compose.LogConsumer, services []string) compose.LogConsumer { + if len(services) == 0 { + return consumer + } + allowed := map[string]bool{} + for _, s := range services { + allowed[s] = true + } + return &allowListLogConsumer{ + allowList: allowed, + delegate: consumer, + } +} + +type allowListLogConsumer struct { + allowList map[string]bool + delegate compose.LogConsumer +} + +func (a *allowListLogConsumer) Log(service, container, message string) { + if a.allowList[service] { + a.delegate.Log(service, container, message) + } +} diff --git a/example/backend.go b/example/backend.go index 23274f11d..646a1d5bc 100644 --- a/example/backend.go +++ b/example/backend.go @@ -175,7 +175,7 @@ func (cs *composeService) Ps(ctx context.Context, projectName string) ([]compose func (cs *composeService) List(ctx context.Context, project string) ([]compose.Stack, error) { return nil, errdefs.ErrNotImplemented } -func (cs *composeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer) error { +func (cs *composeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { return errdefs.ErrNotImplemented } diff --git a/local/compose/logs.go b/local/compose/logs.go index 6d59a8334..c3c395d3c 100644 --- a/local/compose/logs.go +++ b/local/compose/logs.go @@ -29,18 +29,31 @@ import ( "golang.org/x/sync/errgroup" ) -func (s *composeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer) error { +func (s *composeService) Logs(ctx context.Context, projectName string, consumer compose.LogConsumer, options compose.LogOptions) error { list, err := s.apiClient.ContainerList(ctx, types.ContainerListOptions{ Filters: filters.NewArgs( projectFilter(projectName), ), }) + + ignore := func(string) bool { + return false + } + if len(options.Services) > 0 { + ignore = func(s string) bool { + return !contains(options.Services, s) + } + } + if err != nil { return err } eg, ctx := errgroup.WithContext(ctx) for _, c := range list { service := c.Labels[serviceLabel] + if ignore(service) { + continue + } container, err := s.apiClient.ContainerInspect(ctx, c.ID) if err != nil { return err