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 @@