mirror of https://github.com/docker/compose.git
Merge pull request #1073 from docker/logs_service
allow to collect logs for a subset of project services
This commit is contained in:
commit
76ba85fe5d
|
@ -194,7 +194,7 @@ func (cs *aciComposeService) List(ctx context.Context, project string) ([]compos
|
||||||
return stacks, nil
|
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
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (c *composeService) Down(context.Context, string) error {
|
||||||
return errdefs.ErrNotImplemented
|
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
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ type Service interface {
|
||||||
// Down executes the equivalent to a `compose down`
|
// Down executes the equivalent to a `compose down`
|
||||||
Down(ctx context.Context, projectName string) error
|
Down(ctx context.Context, projectName string) error
|
||||||
// Logs executes the equivalent to a `compose logs`
|
// 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 executes the equivalent to a `compose ps`
|
||||||
Ps(ctx context.Context, projectName string) ([]ContainerSummary, error)
|
Ps(ctx context.Context, projectName string) ([]ContainerSummary, error)
|
||||||
// List executes the equivalent to a `docker stack ls`
|
// List executes the equivalent to a `docker stack ls`
|
||||||
|
@ -76,6 +76,11 @@ type ServiceStatus struct {
|
||||||
Publishers []PortPublisher
|
Publishers []PortPublisher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogOptions defines optional parameters for the `Log` API
|
||||||
|
type LogOptions struct {
|
||||||
|
Services []string
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// STARTING indicates that stack is being deployed
|
// STARTING indicates that stack is being deployed
|
||||||
STARTING string = "Starting"
|
STARTING string = "Starting"
|
||||||
|
|
|
@ -21,18 +21,18 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/api/client"
|
"github.com/docker/compose-cli/api/client"
|
||||||
|
"github.com/docker/compose-cli/api/compose"
|
||||||
"github.com/docker/compose-cli/formatter"
|
"github.com/docker/compose-cli/formatter"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func logsCommand() *cobra.Command {
|
func logsCommand() *cobra.Command {
|
||||||
opts := composeOptions{}
|
opts := composeOptions{}
|
||||||
logsCmd := &cobra.Command{
|
logsCmd := &cobra.Command{
|
||||||
Use: "logs",
|
Use: "logs [service...]",
|
||||||
Short: "View output from containers",
|
Short: "View output from containers",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
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")
|
logsCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name")
|
||||||
|
@ -42,7 +42,7 @@ func logsCommand() *cobra.Command {
|
||||||
return logsCmd
|
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)
|
c, err := client.NewWithDefaultLocalBackend(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -53,5 +53,7 @@ func runLogs(ctx context.Context, opts composeOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
consumer := formatter.NewLogConsumer(ctx, os.Stdout)
|
consumer := formatter.NewLogConsumer(ctx, os.Stdout)
|
||||||
return c.ComposeService().Logs(ctx, projectName, consumer)
|
return c.ComposeService().Logs(ctx, projectName, consumer, compose.LogOptions{
|
||||||
|
Services: services,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,7 @@ services:
|
||||||
return cmd.Run()
|
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{
|
list, err := e.moby.ContainerList(ctx, types2.ContainerListOptions{
|
||||||
Filters: filters.NewArgs(filters.Arg("label", "com.docker.compose.project="+projectName)),
|
Filters: filters.NewArgs(filters.Arg("label", "com.docker.compose.project="+projectName)),
|
||||||
})
|
})
|
||||||
|
|
30
ecs/logs.go
30
ecs/logs.go
|
@ -22,7 +22,35 @@ import (
|
||||||
"github.com/docker/compose-cli/api/compose"
|
"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)
|
err := b.aws.GetLogs(ctx, projectName, consumer.Log)
|
||||||
return err
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
func (cs *composeService) List(ctx context.Context, project string) ([]compose.Stack, error) {
|
||||||
return nil, errdefs.ErrNotImplemented
|
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
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,31 @@ import (
|
||||||
"golang.org/x/sync/errgroup"
|
"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{
|
list, err := s.apiClient.ContainerList(ctx, types.ContainerListOptions{
|
||||||
Filters: filters.NewArgs(
|
Filters: filters.NewArgs(
|
||||||
projectFilter(projectName),
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
eg, ctx := errgroup.WithContext(ctx)
|
eg, ctx := errgroup.WithContext(ctx)
|
||||||
for _, c := range list {
|
for _, c := range list {
|
||||||
service := c.Labels[serviceLabel]
|
service := c.Labels[serviceLabel]
|
||||||
|
if ignore(service) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
container, err := s.apiClient.ContainerInspect(ctx, c.ID)
|
container, err := s.apiClient.ContainerInspect(ctx, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Reference in New Issue