diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index a9ad4ac69..12b31972d 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -307,30 +307,23 @@ func (b *BaseApi) Inspect(c *gin.Context) { helper.SuccessWithData(c, result) } -// @Tags Container -// @Summary Container logs -// @Description 容器日志 -// @Accept json -// @Param request body dto.ContainerLog true "request" -// @Success 200 {string} logs -// @Security ApiKeyAuth -// @Router /containers/search/log [post] func (b *BaseApi) ContainerLogs(c *gin.Context) { - var req dto.ContainerLog - if err := c.ShouldBindJSON(&req); err != nil { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) - return - } - if err := global.VALID.Struct(req); err != nil { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) - return - } - logs, err := containerService.ContainerLogs(req) + wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil) if err != nil { - helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + global.LOG.Errorf("gin context http handler failed, err: %v", err) + return + } + defer wsConn.Close() + + container := c.Query("container") + since := c.Query("since") + follow := c.Query("follow") == "true" + tail := c.Query("tail") + + if err := containerService.ContainerLogs(wsConn, container, since, tail, follow); err != nil { + _ = wsConn.WriteMessage(1, []byte(err.Error())) return } - helper.SuccessWithData(c, logs) } // @Tags Container Network diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index c77a3f8dd..cc970b98e 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -69,11 +69,6 @@ type PortHelper struct { Protocol string `json:"protocol"` } -type ContainerLog struct { - ContainerID string `json:"containerID" validate:"required"` - Mode string `json:"mode" validate:"required"` -} - type ContainerOperation struct { Name string `json:"name" validate:"required"` Operation string `json:"operation" validate:"required,oneof=start stop restart kill pause unpause rename remove"` diff --git a/backend/app/service/container.go b/backend/app/service/container.go index 9909cb58a..e0516561f 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -1,9 +1,9 @@ package service import ( + "bufio" "context" "encoding/json" - "errors" "fmt" "io" "os" @@ -26,6 +26,7 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" + "github.com/gorilla/websocket" v1 "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -42,7 +43,7 @@ type IContainerService interface { ContainerCreate(req dto.ContainerCreate) error ContainerLogClean(req dto.OperationWithName) error ContainerOperation(req dto.ContainerOperation) error - ContainerLogs(param dto.ContainerLog) (string, error) + ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error ContainerStats(id string) (*dto.ContainterStats, error) Inspect(req dto.InspectReq) (string, error) DeleteNetwork(req dto.BatchDelete) error @@ -332,16 +333,43 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error { return nil } -func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) { - cmd := exec.Command("docker", "logs", req.ContainerID) - if req.Mode != "all" { - cmd = exec.Command("docker", "logs", req.ContainerID, "--since", req.Mode) +func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error { + command := fmt.Sprintf("docker logs %s", container) + if tail != "0" { + command += " -n " + tail } - stdout, err := cmd.CombinedOutput() + 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 "", errors.New(string(stdout)) + return err } - return string(stdout), nil + if err := cmd.Start(); err != nil { + return err + } + + reader := bufio.NewReader(stdout) + for { + bytes, err := reader.ReadBytes('\n') + if err != nil { + if err == io.EOF { + break + } + global.LOG.Errorf("read bytes from container log failed, err: %v", err) + continue + } + if err = wsConn.WriteMessage(websocket.TextMessage, bytes); 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.ContainterStats, error) { diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index bf3ae9c5d..b8621dd82 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -20,7 +20,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("", baseApi.ContainerCreate) baRouter.POST("/search", baseApi.SearchContainer) - baRouter.POST("/search/log", baseApi.ContainerLogs) + baRouter.GET("/search/log", baseApi.ContainerLogs) baRouter.POST("/clean/log", baseApi.CleanContainerLog) baRouter.POST("/inspect", baseApi.Inspect) baRouter.POST("/operate", baseApi.ContainerOperation) diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index c80207211..9ec1d7ce1 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -473,6 +473,9 @@ const message = { container: 'Container', upTime: 'UpTime', all: 'All', + fetch: 'Fetch', + lines: 'Lines', + linesHelper: 'Please enter the correct number of logs to retrieve!', lastDay: 'Last Day', last4Hour: 'Last 4 Hours', lastHour: 'Last Hour', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index e7f525265..f1f71eca7 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -480,6 +480,9 @@ const message = { container: '容器', upTime: '运行时长', all: '全部', + fetch: '过滤', + lines: '条数', + linesHelper: '请输入正确的日志获取条数!', lastDay: '最近一天', last4Hour: '最近 4 小时', lastHour: '最近 1 小时', diff --git a/frontend/src/views/container/container/log/index.vue b/frontend/src/views/container/container/log/index.vue index 3a6757a5f..bdc585e81 100644 --- a/frontend/src/views/container/container/log/index.vue +++ b/frontend/src/views/container/container/log/index.vue @@ -15,10 +15,23 @@