Skip to content

Commit

Permalink
feat: 获取应用日志 (#1691)
Browse files Browse the repository at this point in the history
  • Loading branch information
SheepSheepChen authored Nov 1, 2024
1 parent 17960ab commit 475ad2b
Show file tree
Hide file tree
Showing 14 changed files with 239 additions and 3 deletions.
26 changes: 26 additions & 0 deletions cnb-builder-shim/internal/devsandbox/webserver/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* TencentBlueKing is pleased to support the open source community by making
* 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available.
* Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* We undertake not to change the open source license (MIT license) applicable
* to the current version of the project delivered to anyone in the future.
*/

package webserver

// LogQueryParams : log query params
// It includes the following fields:
// - lines: Specifies the number of log lines to retrieve
type LogQueryParams struct {
Lines int `form:"lines,default=100" binding:"omitempty,gte=1,lte=200"`
}
22 changes: 22 additions & 0 deletions cnb-builder-shim/internal/devsandbox/webserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func New(lg *logr.Logger) (*WebServer, error) {
mgr := service.NewDeployManager()
r.POST("/deploys", DeployHandler(s, mgr))
r.GET("/deploys/:deployID/results", ResultHandler(mgr))
r.GET("/app_logs", AppLogHandler())

return s, nil
}
Expand Down Expand Up @@ -208,4 +209,25 @@ func ResultHandler(svc service.DeployServiceHandler) gin.HandlerFunc {
}
}

// AppLogHandler 获取 app 日志
func AppLogHandler() gin.HandlerFunc {
return func(c *gin.Context) {
var queryParams LogQueryParams
if err := c.ShouldBindQuery(&queryParams); err != nil {
// 验证失败
c.JSON(http.StatusBadRequest, gin.H{
"message": "查询参数无效,lines 必须是 1 到 200 之间的整数",
})
return
}
// 读取日志
logs, err := service.GetAppLogs(service.DefaultAppLogDir, queryParams.Lines)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"message": fmt.Sprintf("get app log error: %s", err.Error())})
return
}
c.JSON(http.StatusOK, gin.H{"logs": logs})
}
}

var _ devsandbox.DevWatchServer = (*WebServer)(nil)
107 changes: 107 additions & 0 deletions cnb-builder-shim/internal/devsandbox/webserver/service/app_logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* TencentBlueKing is pleased to support the open source community by making
* 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available.
* Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* We undertake not to change the open source license (MIT license) applicable
* to the current version of the project delivered to anyone in the future.
*/

package service

import (
"os"
"path/filepath"
"strings"

"github.com/docker/docker/pkg/tailfile"
)

// DefaultAppLogDir 应用日志默认目录
var DefaultAppLogDir = "/cnb/devsandbox/supervisor/log"

// GetAppLogs 获取应用日志
// Parameters:
// - logPath: 日志路径
// - lines: 需要的日志行数
//
// Returns:
// - map[string][]string: key 为日志类型, value 为日志内容
func GetAppLogs(logDir string, lines int) (map[string][]string, error) {
// 检查文件是否存在
if _, err := os.Stat(logDir); os.IsNotExist(err) {
// 文件不存在,返回 nil, nil
return nil, nil
}
logs := make(map[string][]string)
logFiles, err := getLogFiles(logDir)
if err != nil {
return nil, err
}
for logType, file := range logFiles {
logPath := filepath.Join(logDir, file.Name())
logLines, err := tailFile(logPath, lines)
if err != nil {
return nil, err
}
logs[logType] = logLines
}
return logs, nil
}

// 按日志类型分类日志文件
func getLogFiles(logDir string) (map[string]os.FileInfo, error) {
logFiles := make(map[string]os.FileInfo)
err := filepath.Walk(logDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 获取日志类型
logType := getLogType(info)
if logType != "" {
logFiles[logType] = info
}
return nil
})
if err != nil {
return nil, err
}
return logFiles, nil
}

// 通过文件名称获取日志类型, 需要符合格式:{{type}}.log
func getLogType(info os.FileInfo) string {
if !info.IsDir() && strings.HasSuffix(strings.ToLower(info.Name()), ".log") {
logType := strings.TrimSuffix(strings.ToLower(info.Name()), filepath.Ext(info.Name()))
return logType
}
return ""
}

// 获取文件最新部分的内容
func tailFile(filePath string, lines int) (logs []string, err error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
tailBytes, err := tailfile.TailFile(file, lines)
if err != nil {
return nil, err
}
tailStr := make([]string, len(tailBytes))
for index, b := range tailBytes {
tailStr[index] = string(b)
}

logs = append(logs, tailStr...)
return logs, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* TencentBlueKing is pleased to support the open source community by making
* 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available.
* Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* We undertake not to change the open source license (MIT license) applicable
* to the current version of the project delivered to anyone in the future.
*/

package service

import (
"os"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Test GetAppLogs", func() {
var err error
var logPath string
var celeryLogPath string
var mysqlLogPath string
BeforeEach(func() {
logPath, err = os.MkdirTemp("", "log_test")
Expect(err).To(BeNil())
celeryLogPath = filepath.Join(logPath, "celery.log")
mysqlLogPath = filepath.Join(logPath, "mysql.log")
logContent1 := "value1\nvalue2\n"
logContent2 := "value3\nvalue4\n"
err := os.WriteFile(celeryLogPath, []byte(logContent1), 0644)
Expect(err).To(BeNil())
err = os.WriteFile(mysqlLogPath, []byte(logContent2), 0644)
Expect(err).To(BeNil())
})
AfterEach(func() {
Expect(os.RemoveAll(logPath)).To(BeNil())
})
Describe("Test GetAppLogs", func() {
It("test lines < logs", func() {
logs, err := GetAppLogs(logPath, 1)
Expect(err).To(BeNil())
Expect(len(logs["celery"])).To(Equal(1))
Expect(logs["celery"]).To(Equal([]string{"value2"}))
Expect(len(logs["mysql"])).To(Equal(1))
Expect(logs["mysql"]).To(Equal([]string{"value4"}))
})
It("test lines > logs", func() {
logs, err := GetAppLogs(logPath, 5)
Expect(err).To(BeNil())
Expect(len(logs["celery"])).To(Equal(2))
Expect(logs["celery"]).To(Equal([]string{"value1", "value2"}))
Expect(len(logs["mysql"])).To(Equal(2))
Expect(logs["mysql"]).To(Equal([]string{"value3", "value4"}))
})
It("logFile does not exist", func() {
logs, err := GetAppLogs("", 5)
Expect(err).To(BeNil())
Expect(logs).To(BeNil())
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var _ = Describe("Test DeployManager", func() {
var m *DeployManager
var tmpAppDir string

testSrcFilePath := filepath.Join("testdata", "templates", "django-helloworld")
testSrcFilePath := filepath.Join("testdata", "helloworld")
oldAppDir := devsandbox.DefaultAppDir

BeforeEach(func() {
Expand All @@ -55,12 +55,13 @@ var _ = Describe("Test DeployManager", func() {

Describe("Test deploy", func() {
It("test deploy", func() {
result, _ := m.Deploy(testSrcFilePath)
result, err := m.Deploy(testSrcFilePath)
Expect(err).To(BeNil())

Expect(len(result.DeployID)).To(Equal(32))
Expect(result.Status).To(Equal(devsandbox.ReloadProcessing))

_, err := os.Stat(path.Join(devsandbox.DefaultAppDir, "Procfile"))
_, err = os.Stat(path.Join(devsandbox.DefaultAppDir, "Procfile"))
Expect(err).To(BeNil())

// 验证隐藏目录不会被覆盖(删除)
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
spec_version: 2
module:
language: Python
scripts:
pre_release_hook: "python manage.py migrate --no-input"
processes:
web:
command: python manage.py runserver 0.0.0.0:8080

0 comments on commit 475ad2b

Please sign in to comment.