From e8ee373fc4a8d2211ae649535366525a274915e9 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:29:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A4=84=E7=90=86=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=AF=BC=E8=87=B4=E7=9A=84=E5=83=B5=E5=B0=B8?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=20(#2847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #2846 --- backend/app/api/v1/container.go | 4 +- backend/app/service/container.go | 57 ++++++++++++++----- backend/app/service/container_compose.go | 43 -------------- frontend/src/components/compose-log/index.vue | 10 +--- .../src/components/container-log/index.vue | 2 +- .../views/container/container/log/index.vue | 7 ++- 6 files changed, 53 insertions(+), 70 deletions(-) diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index ddffe07ba..78062c2d6 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -434,7 +434,7 @@ func (b *BaseApi) ContainerLogs(c *gin.Context) { follow := c.Query("follow") == "true" tail := c.Query("tail") - if err := containerService.ContainerLogs(wsConn, container, since, tail, follow); err != nil { + if err := containerService.ContainerLogs(wsConn, "container", container, since, tail, follow); err != nil { _ = wsConn.WriteMessage(1, []byte(err.Error())) return } @@ -658,7 +658,7 @@ func (b *BaseApi) ComposeLogs(c *gin.Context) { follow := c.Query("follow") == "true" tail := c.Query("tail") - if err := containerService.ComposeLogs(wsConn, compose, since, tail, follow); err != nil { + if err := containerService.ContainerLogs(wsConn, "compose", compose, since, tail, follow); err != nil { _ = wsConn.WriteMessage(1, []byte(err.Error())) return } diff --git a/backend/app/service/container.go b/backend/app/service/container.go index f3272172b..c5dc18f43 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "sync" + "syscall" "time" "github.com/1Panel-dev/1Panel/backend/app/dto" @@ -55,7 +56,7 @@ type IContainerService interface { ContainerRename(req dto.ContainerRename) error ContainerLogClean(req dto.OperationWithName) error ContainerOperation(req dto.ContainerOperation) error - ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error + ContainerLogs(wsConn *websocket.Conn, containerType, container, since, tail string, follow bool) error ContainerStats(id string) (*dto.ContainerStats, error) Inspect(req dto.InspectReq) (string, error) DeleteNetwork(req dto.BatchDelete) error @@ -67,7 +68,6 @@ type IContainerService interface { Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) LoadContainerLogs(req dto.OperationWithNameAndType) string - ComposeLogs(wsConn *websocket.Conn, composePath, since, tail string, follow bool) error } func NewIContainerService() IContainerService { @@ -592,11 +592,15 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error { return nil } -func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error { +func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType, container, since, tail string, follow bool) error { + defer func() { wsConn.Close() }() if cmd.CheckIllegal(container, since, tail) { return buserr.New(constant.ErrCmdIllegal) } command := fmt.Sprintf("docker logs %s", container) + if containerType == "compose" { + command = fmt.Sprintf("docker-compose -f %s logs", container) + } if tail != "0" { command += " --tail " + tail } @@ -608,6 +612,14 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, sinc } command += " 2>&1" cmd := exec.Command("bash", "-c", command) + if !follow { + stdout, _ := cmd.CombinedOutput() + if err := wsConn.WriteMessage(websocket.TextMessage, stdout); err != nil { + global.LOG.Errorf("send message with log to ws failed, err: %v", err) + } + return nil + } + stdout, err := cmd.StdoutPipe() if err != nil { return err @@ -615,23 +627,40 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, sinc if err := cmd.Start(); err != nil { return err } + defer func() { + _ = cmd.Process.Signal(syscall.SIGTERM) + _ = cmd.Wait() + }() + var exitCh chan struct{} + if follow { + go func() { + _, wsData, _ := wsConn.ReadMessage() + if string(wsData) == "close conn" { + exitCh <- struct{}{} + } + }() + } buffer := make([]byte, 1024) for { - n, err := stdout.Read(buffer) - if err != nil { - if err == io.EOF { - break + select { + case <-exitCh: + return nil + default: + n, err := stdout.Read(buffer) + if err != nil { + if err == io.EOF { + return err + } + global.LOG.Errorf("read bytes from log failed, err: %v", err) + continue + } + if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil { + global.LOG.Errorf("send message with log to ws failed, err: %v", err) + return err } - global.LOG.Errorf("read bytes from container log failed, err: %v", err) - continue - } - if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil { - global.LOG.Errorf("send message with container log to ws failed, err: %v", err) - break } } - return nil } func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) { diff --git a/backend/app/service/container_compose.go b/backend/app/service/container_compose.go index c74cd28ec..b0d651d4a 100644 --- a/backend/app/service/container_compose.go +++ b/backend/app/service/container_compose.go @@ -4,7 +4,6 @@ import ( "bufio" "errors" "fmt" - "github.com/gorilla/websocket" "io" "os" "os/exec" @@ -262,45 +261,3 @@ func (u *ContainerService) loadPath(req *dto.ComposeCreate) error { } return nil } - -func (u *ContainerService) ComposeLogs(wsConn *websocket.Conn, composePath, since, tail string, follow bool) error { - if cmd.CheckIllegal(composePath, since, tail) { - return buserr.New(constant.ErrCmdIllegal) - } - command := fmt.Sprintf("docker-compose -f %s logs", composePath) - if tail != "0" { - command += " --tail " + tail - } - if since != "all" { - command += " --since " + since - } - if follow { - command += " -f" - } - command += " 2>&1" - cmd := exec.Command("bash", "-c", command) - stdout, err := cmd.StdoutPipe() - if err != nil { - return err - } - if err := cmd.Start(); err != nil { - return err - } - - buffer := make([]byte, 1024) - for { - n, err := stdout.Read(buffer) - if err != nil { - if err == io.EOF { - break - } - global.LOG.Errorf("read bytes from compose log failed, err: %v", err) - continue - } - if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil { - global.LOG.Errorf("send message with compose log to ws failed, err: %v", err) - break - } - } - return nil -} diff --git a/frontend/src/components/compose-log/index.vue b/frontend/src/components/compose-log/index.vue index b4dc6d141..f8a54509a 100644 --- a/frontend/src/components/compose-log/index.vue +++ b/frontend/src/components/compose-log/index.vue @@ -1,5 +1,5 @@