Repository: docker/compose-cli
Pull request #1433 (2021-03-16 15:01:54)

use "container name witout project" for both logs and events
**What I did**

adopted "container name without project" as the canonical name for both logs prefixes and lifecycle event

**Related issue**
https://github.com/docker/compose-cli/issues/1405

**(not mandatory) A picture of a cute animal, if possible in relation with what you did**



Patch:
diff --git a/api/compose/api.go b/api/compose/api.go
index 06eb6e3c..c6269328 100644
--- a/api/compose/api.go
+++ b/api/compose/api.go
@@ -314,22 +314,21 @@ type Stack struct {
 
 // LogConsumer is a callback to process log messages from services
 type LogConsumer interface {
-	Log(name, service, container, message string)
-	Status(name, container, msg string)
-	Register(name string, source string)
+	Log(service, container, message string)
+	Status(container, msg string)
+	Register(container string)
 }
 
 // ContainerEventListener is a callback to process ContainerEvent from services
 type ContainerEventListener func(event ContainerEvent)
 
-// ContainerEvent notify an event has been collected on Source container implementing Service
+// ContainerEvent notify an event has been collected on source container implementing Service
 type ContainerEvent struct {
-	Type     int
-	Source   string
-	Service  string
-	Name     string
-	Line     string
-	ExitCode int
+	Type      int
+	Container string
+	Service   string
+	Line      string
+	ExitCode  int
 }
 
 const (
diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go
index 55955775..280bb4dd 100644
--- a/cli/cmd/compose/up.go
+++ b/cli/cmd/compose/up.go
@@ -399,11 +399,11 @@ func (p printer) run(ctx context.Context, cascadeStop bool, exitCodeFrom string,
 		case compose.UserCancel:
 			aborting = true
 		case compose.ContainerEventAttach:
-			consumer.Register(event.Name, event.Source)
+			consumer.Register(event.Container)
 			count++
 		case compose.ContainerEventExit:
 			if !aborting {
-				consumer.Status(event.Name, event.Source, fmt.Sprintf("exited with code %d", event.ExitCode))
+				consumer.Status(event.Container, fmt.Sprintf("exited with code %d", event.ExitCode))
 			}
 			if cascadeStop {
 				if !aborting {
@@ -426,7 +426,7 @@ func (p printer) run(ctx context.Context, cascadeStop bool, exitCodeFrom string,
 			}
 		case compose.ContainerEventLog:
 			if !aborting {
-				consumer.Log(event.Name, event.Service, event.Source, event.Line)
+				consumer.Log(event.Container, event.Service, event.Line)
 			}
 		}
 	}
diff --git a/cli/formatter/logs.go b/cli/formatter/logs.go
index b0d377f8..56893f64 100644
--- a/cli/formatter/logs.go
+++ b/cli/formatter/logs.go
@@ -38,11 +38,11 @@ func NewLogConsumer(ctx context.Context, w io.Writer, color bool, prefix bool) c
 	}
 }
 
-func (l *logConsumer) Register(name string, id string) {
-	l.register(name, id)
+func (l *logConsumer) Register(name string) {
+	l.register(name)
 }
 
-func (l *logConsumer) register(name string, id string) *presenter {
+func (l *logConsumer) register(name string) *presenter {
 	cf := monochrome
 	if l.color {
 		cf = nextColor()
@@ -51,7 +51,7 @@ func (l *logConsumer) register(name string, id string) *presenter {
 		colors: cf,
 		name:   name,
 	}
-	l.presenters[id] = p
+	l.presenters[name] = p
 	if l.prefix {
 		l.computeWidth()
 		for _, p := range l.presenters {
@@ -62,25 +62,25 @@ func (l *logConsumer) register(name string, id string) *presenter {
 }
 
 // Log formats a log message as received from name/container
-func (l *logConsumer) Log(name, service, container, message string) {
+func (l *logConsumer) Log(container, service, message string) {
 	if l.ctx.Err() != nil {
 		return
 	}
 	p, ok := l.presenters[container]
 	if !ok { // should have been registered, but ¯\_(ツ)_/¯
-		p = l.register(name, container)
+		p = l.register(container)
 	}
 	for _, line := range strings.Split(message, "\n") {
 		fmt.Fprintf(l.writer, "%s %s\n", p.prefix, line) // nolint:errcheck
 	}
 }
 
-func (l *logConsumer) Status(name, id, msg string) {
-	p, ok := l.presenters[id]
+func (l *logConsumer) Status(container, msg string) {
+	p, ok := l.presenters[container]
 	if !ok {
-		p = l.register(name, id)
+		p = l.register(container)
 	}
-	s := p.colors(fmt.Sprintf("%s %s\n", name, msg))
+	s := p.colors(fmt.Sprintf("%s %s\n", container, msg))
 	l.writer.Write([]byte(s)) // nolint:errcheck
 }
 
diff --git a/ecs/aws.go b/ecs/aws.go
index 6e8ba841..1955318d 100644
--- a/ecs/aws.go
+++ b/ecs/aws.go
@@ -63,7 +63,7 @@ type API interface {
 	InspectSecret(ctx context.Context, id string) (secrets.Secret, error)
 	ListSecrets(ctx context.Context) ([]secrets.Secret, error)
 	DeleteSecret(ctx context.Context, id string, recover bool) error
-	GetLogs(ctx context.Context, name string, consumer func(name string, service string, container string, message string), follow bool) error
+	GetLogs(ctx context.Context, name string, consumer func(container string, service string, message string), follow bool) error
 	DescribeService(ctx context.Context, cluster string, arn string) (compose.ServiceStatus, error)
 	DescribeServiceTasks(ctx context.Context, cluster string, project string, service string) ([]compose.ContainerSummary, error)
 	getURLWithPortMapping(ctx context.Context, targetGroupArns []string) ([]compose.PortPublisher, error)
diff --git a/ecs/aws_mock.go b/ecs/aws_mock.go
index 568c60a7..03c5e322 100644
--- a/ecs/aws_mock.go
+++ b/ecs/aws_mock.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/docker/compose-cli/ecs (interfaces: API)
+// Container: github.com/docker/compose-cli/ecs (interfaces: API)
 
 // Package ecs is a generated GoMock package.
 package ecs
@@ -285,7 +285,7 @@ func (mr *MockAPIMockRecorder) GetLoadBalancerURL(arg0, arg1 interface{}) *gomoc
 }
 
 // GetLogs mocks base method
-func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 func(string, string, string, string), arg3 bool) error {
+func (m *MockAPI) GetLogs(arg0 context.Context, arg1 string, arg2 func(string, string, string), arg3 bool) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "GetLogs", arg0, arg1, arg2, arg3)
 	ret0, _ := ret[0].(error)
diff --git a/ecs/sdk.go b/ecs/sdk.go
index 43a45425..5f836274 100644
--- a/ecs/sdk.go
+++ b/ecs/sdk.go
@@ -805,7 +805,7 @@ func (s sdk) DeleteSecret(ctx context.Context, id string, recover bool) error {
 	return err
 }
 
-func (s sdk) GetLogs(ctx context.Context, name string, consumer func(name string, service string, container string, message string), follow bool) error {
+func (s sdk) GetLogs(ctx context.Context, name string, consumer func(container string, service string, message string), follow bool) error {
 	logGroup := fmt.Sprintf("/docker-compose/%s", name)
 	var startTime int64
 	for {
@@ -832,7 +832,7 @@ func (s sdk) GetLogs(ctx context.Context, name string, consumer func(name string
 
 				for _, event := range events.Events {
 					p := strings.Split(aws.StringValue(event.LogStreamName), "/")
-					consumer(p[1], p[1], p[2], aws.StringValue(event.Message))
+					consumer(p[1], p[2], aws.StringValue(event.Message))
 					startTime = *event.IngestionTime
 				}
 			}
diff --git a/kube/client/client.go b/kube/client/client.go
index 98b49694..fdffc347 100644
--- a/kube/client/client.go
+++ b/kube/client/client.go
@@ -96,8 +96,8 @@ func (kc *KubeClient) GetLogs(ctx context.Context, projectName string, consumer
 	for _, pod := range pods.Items {
 		request := kc.client.CoreV1().Pods(kc.namespace).GetLogs(pod.Name, &corev1.PodLogOptions{Follow: follow})
 		service := pod.Labels[compose.ServiceTag]
-		w := utils.GetWriter(pod.Name, service, string(pod.UID), func(event compose.ContainerEvent) {
-			consumer.Log(event.Name, event.Service, event.Source, event.Line)
+		w := utils.GetWriter(pod.Name, service, func(event compose.ContainerEvent) {
+			consumer.Log(event.Container, event.Service, event.Line)
 		})
 
 		eg.Go(func() error {
diff --git a/local/compose/attach.go b/local/compose/attach.go
index 95e3f0a1..fe0bebc2 100644
--- a/local/compose/attach.go
+++ b/local/compose/attach.go
@@ -41,7 +41,7 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis
 
 	var names []string
 	for _, c := range containers {
-		names = append(names, getCanonicalContainerName(c))
+		names = append(names, getContainerNameWithoutProject(c))
 	}
 
 	fmt.Printf("Attaching to %s\n", strings.Join(names, ", "))
@@ -95,7 +95,7 @@ func (s *composeService) attach(ctx context.Context, project *types.Project, lis
 
 func (s *composeService) attachContainer(ctx context.Context, container moby.Container, listener compose.ContainerEventListener, project *types.Project) error {
 	serviceName := container.Labels[serviceLabel]
-	w := utils.GetWriter(getContainerNameWithoutProject(container), serviceName, container.ID, listener)
+	w := utils.GetWriter(getContainerNameWithoutProject(container), serviceName, listener)
 
 	service, err := project.GetService(serviceName)
 	if err != nil {
@@ -103,10 +103,9 @@ func (s *composeService) attachContainer(ctx context.Context, container moby.Con
 	}
 
 	listener(compose.ContainerEvent{
-		Type:    compose.ContainerEventAttach,
-		Source:  container.ID,
-		Name:    getContainerNameWithoutProject(container),
-		Service: container.Labels[serviceLabel],
+		Type:      compose.ContainerEventAttach,
+		Container: getContainerNameWithoutProject(container),
+		Service:   container.Labels[serviceLabel],
 	})
 
 	return s.attachContainerStreams(ctx, container.ID, service.Tty, nil, w)
diff --git a/local/compose/logs.go b/local/compose/logs.go
index ae71d30e..7559283e 100644
--- a/local/compose/logs.go
+++ b/local/compose/logs.go
@@ -76,8 +76,8 @@ func (s *composeService) Logs(ctx context.Context, projectName string, consumer
 				return err
 			}
 			name := getContainerNameWithoutProject(c)
-			w := utils.GetWriter(name, service, c.ID, func(event compose.ContainerEvent) {
-				consumer.Log(name, event.Service, event.Name, event.Line)
+			w := utils.GetWriter(name, service, func(event compose.ContainerEvent) {
+				consumer.Log(name, service, event.Line)
 			})
 			if container.Config.Tty {
 				_, err = io.Copy(w, r)
diff --git a/local/compose/start.go b/local/compose/start.go
index 4716ca87..b15785d9 100644
--- a/local/compose/start.go
+++ b/local/compose/start.go
@@ -59,15 +59,14 @@ func (s *composeService) Start(ctx context.Context, project *types.Project, opti
 
 func (s *composeService) waitContainer(ctx context.Context, c moby.Container, listener compose.ContainerEventListener) {
 	statusC, errC := s.apiClient.ContainerWait(ctx, c.ID, container.WaitConditionNotRunning)
-	name := getCanonicalContainerName(c)
+	name := getContainerNameWithoutProject(c)
 	select {
 	case status := <-statusC:
 		listener(compose.ContainerEvent{
-			Type:     compose.ContainerEventExit,
-			Source:   c.ID,
-			Name:     name,
-			Service:  c.Labels[serviceLabel],
-			ExitCode: int(status.StatusCode),
+			Type:      compose.ContainerEventExit,
+			Container: name,
+			Service:   c.Labels[serviceLabel],
+			ExitCode:  int(status.StatusCode),
 		})
 	case err := <-errC:
 		logrus.Warnf("Unexpected API error for %s : %s", name, err.Error())
diff --git a/local/mocks/mock_docker_api.go b/local/mocks/mock_docker_api.go
index f7ff8f4b..398138a7 100644
--- a/local/mocks/mock_docker_api.go
+++ b/local/mocks/mock_docker_api.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/docker/docker/client (interfaces: APIClient)
+// Container: github.com/docker/docker/client (interfaces: APIClient)
 
 // Package mocks is a generated GoMock package.
 package mocks
diff --git a/utils/logs.go b/utils/logs.go
index 7593f748..d1e76df8 100644
--- a/utils/logs.go
+++ b/utils/logs.go
@@ -43,29 +43,28 @@ type allowListLogConsumer struct {
 	delegate  compose.LogConsumer
 }
 
-func (a *allowListLogConsumer) Log(name, service, container, message string) {
+func (a *allowListLogConsumer) Log(container, service, message string) {
 	if a.allowList[service] {
-		a.delegate.Log(name, service, container, message)
+		a.delegate.Log(container, service, message)
 	}
 }
 
-func (a *allowListLogConsumer) Status(name, container, message string) {
-	if a.allowList[name] {
-		a.delegate.Status(name, container, message)
+func (a *allowListLogConsumer) Status(container, message string) {
+	if a.allowList[container] {
+		a.delegate.Status(container, message)
 	}
 }
 
-func (a *allowListLogConsumer) Register(name string, source string) {
+func (a *allowListLogConsumer) Register(name string) {
 	if a.allowList[name] {
-		a.delegate.Register(name, source)
+		a.delegate.Register(name)
 	}
 }
 
 // GetWriter creates a io.Writer that will actually split by line and format by LogConsumer
-func GetWriter(name, service, container string, events compose.ContainerEventListener) io.Writer {
+func GetWriter(container, service string, events compose.ContainerEventListener) io.Writer {
 	return &splitBuffer{
 		buffer:    bytes.Buffer{},
-		name:      name,
 		service:   service,
 		container: container,
 		consumer:  events,
@@ -74,7 +73,6 @@ func GetWriter(name, service, container string, events compose.ContainerEventLis
 
 type splitBuffer struct {
 	buffer    bytes.Buffer
-	name      string
 	service   string
 	container string
 	consumer  compose.ContainerEventListener
@@ -94,11 +92,10 @@ func (s *splitBuffer) Write(b []byte) (int, error) {
 		}
 		line := s.buffer.Next(index + 1)
 		s.consumer(compose.ContainerEvent{
-			Type:    compose.ContainerEventLog,
-			Name:    s.name,
-			Service: s.service,
-			Source:  s.container,
-			Line:    string(line[:len(line)-1]),
+			Type:      compose.ContainerEventLog,
+			Service:   s.service,
+			Container: s.container,
+			Line:      string(line[:len(line)-1]),
 		})
 	}
 	return n, nil
diff --git a/utils/prompt/prompt_mock.go b/utils/prompt/prompt_mock.go
index b2f2ea7c..7e547177 100644
--- a/utils/prompt/prompt_mock.go
+++ b/utils/prompt/prompt_mock.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/docker/compose-cli/prompt (interfaces: UI)
+// Container: github.com/docker/compose-cli/prompt (interfaces: UI)
 
 // Package prompt is a generated GoMock package.
 package prompt


Test patch:
diff --git a/local/e2e/compose/compose_test.go b/local/e2e/compose/compose_test.go
index 41db4b1d..f731c41f 100644
--- a/local/e2e/compose/compose_test.go
+++ b/local/e2e/compose/compose_test.go
@@ -140,7 +140,7 @@ func TestAttachRestart(t *testing.T) {
 	res := c.RunDockerOrExitError("compose", "--ansi=never", "--project-directory", "fixtures/attach-restart", "up")
 	output := res.Stdout()
 
-	exitRegex := regexp.MustCompile("attach-restart_another_1 exited with code 1")
+	exitRegex := regexp.MustCompile("another_1 exited with code 1")
 	assert.Equal(t, len(exitRegex.FindAllStringIndex(output, -1)), 3, res.Combined())
 
 	execRegex := regexp.MustCompile(`another_1  \| world`)
diff --git a/utils/logs_test.go b/utils/logs_test.go
index 17113696..f0eaf835 100644
--- a/utils/logs_test.go
+++ b/utils/logs_test.go
@@ -26,7 +26,7 @@ import (
 
 func TestSplitWriter(t *testing.T) {
 	var lines []string
-	w := GetWriter("name", "service", "container", func(event compose.ContainerEvent) {
+	w := GetWriter("container", "service", func(event compose.ContainerEvent) {
 		lines = append(lines, event.Line)
 	})
 	w.Write([]byte("h"))        //nolint: errcheck