迁移日志到MongoDB

This commit is contained in:
marvzhang
2020-04-01 16:52:23 +08:00
parent a9f6967135
commit 63c95f8618
10 changed files with 222 additions and 77 deletions

View File

@@ -34,31 +34,13 @@ func main() {
panic(err) panic(err)
} }
log.Info("initialized config successfully") log.Info("initialized config successfully")
// 初始化日志设置
logLevel := viper.GetString("log.level")
if logLevel != "" {
log.SetLevelFromString(logLevel)
}
log.Info("initialized log config successfully")
if viper.GetString("log.isDeletePeriodically") == "Y" {
err := services.InitDeleteLogPeriodically()
if err != nil {
log.Error("init DeletePeriodically failed")
panic(err)
}
log.Info("initialized periodically cleaning log successfully")
} else {
log.Info("periodically cleaning log is switched off")
}
// 初始化Mongodb数据库 // 初始化Mongodb数据库
if err := database.InitMongo(); err != nil { if err := database.InitMongo(); err != nil {
log.Error("init mongodb error:" + err.Error()) log.Error("init mongodb error:" + err.Error())
debug.PrintStack() debug.PrintStack()
panic(err) panic(err)
} }
log.Info("initialized MongoDB successfully") log.Info("initialized mongodb successfully")
// 初始化Redis数据库 // 初始化Redis数据库
if err := database.InitRedis(); err != nil { if err := database.InitRedis(); err != nil {
@@ -66,7 +48,14 @@ func main() {
debug.PrintStack() debug.PrintStack()
panic(err) panic(err)
} }
log.Info("initialized Redis successfully") log.Info("initialized redis successfully")
// 初始化日志设置
if err := services.InitLogService(); err != nil {
log.Error("init log error:" + err.Error())
panic(err)
}
log.Info("initialized log successfully")
if model.IsMaster() { if model.IsMaster() {
// 初始化定时任务 // 初始化定时任务

View File

@@ -1,12 +1,23 @@
package model package model
import ( import (
"crawlab/database"
"crawlab/utils" "crawlab/utils"
"github.com/apex/log" "github.com/apex/log"
"github.com/globalsign/mgo/bson"
"os" "os"
"runtime/debug" "runtime/debug"
"time"
) )
type LogItem struct {
Id bson.ObjectId `json:"_id" bson:"_id"`
Message string `json:"msg" bson:"msg"`
TaskId string `json:"task_id" bson:"task_id"`
IsError bool `json:"is_error" bson:"is_error"`
Ts time.Time `json:"ts" bson:"ts"`
}
// 获取本地日志 // 获取本地日志
func GetLocalLog(logPath string) (fileBytes []byte, err error) { func GetLocalLog(logPath string) (fileBytes []byte, err error) {
@@ -42,3 +53,27 @@ func GetLocalLog(logPath string) (fileBytes []byte, err error) {
logBuf = logBuf[:n] logBuf = logBuf[:n]
return logBuf, nil return logBuf, nil
} }
func AddLogItem(l LogItem) error {
s, c := database.GetCol("logs")
defer s.Close()
if err := c.Insert(l); err != nil {
log.Errorf("insert log error: " + err.Error())
debug.PrintStack()
return err
}
return nil
}
func GetLogItemList(filter interface{}, skip int, limit int, sortStr string) ([]LogItem, error) {
s, c := database.GetCol("logs")
defer s.Close()
var logItems []LogItem
if err := c.Find(filter).Skip(skip).Limit(limit).Sort(sortStr).All(&logItems); err != nil {
debug.PrintStack()
return logItems, err
}
return logItems, nil
}

View File

@@ -109,6 +109,19 @@ func (t *Task) GetResults(pageNum int, pageSize int) (results []interface{}, tot
return return
} }
func (t *Task) GetLogItems() (logItems []LogItem, err error) {
query := bson.M{
"task_id": t.Id,
}
logItems, err = GetLogItemList(query, 0, constants.Infinite, "+_id")
if err != nil {
return logItems, err
}
return logItems, nil
}
func GetTaskList(filter interface{}, skip int, limit int, sortKey string) ([]Task, error) { func GetTaskList(filter interface{}, skip int, limit int, sortKey string) ([]Task, error) {
s, c := database.GetCol("tasks") s, c := database.GetCol("tasks")
defer s.Close() defer s.Close()

View File

@@ -235,12 +235,12 @@ func DeleteTask(c *gin.Context) {
func GetTaskLog(c *gin.Context) { func GetTaskLog(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
logStr, err := services.GetTaskLog(id) logItems, err := services.GetTaskLog(id)
if err != nil { if err != nil {
HandleError(http.StatusInternalServerError, c, err) HandleError(http.StatusInternalServerError, c, err)
return return
} }
HandleSuccessData(c, logStr) HandleSuccessData(c, logItems)
} }
func GetTaskResults(c *gin.Context) { func GetTaskResults(c *gin.Context) {

View File

@@ -9,6 +9,7 @@ import (
"crawlab/utils" "crawlab/utils"
"encoding/json" "encoding/json"
"github.com/apex/log" "github.com/apex/log"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson" "github.com/globalsign/mgo/bson"
"github.com/spf13/viper" "github.com/spf13/viper"
"io/ioutil" "io/ioutil"
@@ -162,5 +163,42 @@ func InitDeleteLogPeriodically() error {
c.Start() c.Start()
return nil return nil
}
func InitLogIndexes() error {
s, c := database.GetCol("logs")
defer s.Close()
_ = c.EnsureIndexKey("task_id")
_ = c.EnsureIndex(mgo.Index{
Key: []string{"$text:msg"},
})
return nil
}
func InitLogService() error {
logLevel := viper.GetString("log.level")
if logLevel != "" {
log.SetLevelFromString(logLevel)
}
log.Info("initialized log config successfully")
if viper.GetString("log.isDeletePeriodically") == "Y" {
if err := InitDeleteLogPeriodically(); err != nil {
log.Error("init DeletePeriodically failed")
return err
}
log.Info("initialized periodically cleaning log successfully")
} else {
log.Info("periodically cleaning log is switched off")
}
if model.IsMaster() {
if err := InitLogIndexes(); err != nil {
log.Errorf(err.Error())
return err
}
}
return nil
} }

View File

@@ -1,6 +1,7 @@
package services package services
import ( import (
"bufio"
"crawlab/constants" "crawlab/constants"
"crawlab/database" "crawlab/database"
"crawlab/entity" "crawlab/entity"
@@ -160,15 +161,70 @@ func SetEnv(cmd *exec.Cmd, envs []model.Env, task model.Task, spider model.Spide
return cmd return cmd
} }
func SetLogConfig(cmd *exec.Cmd, path string) error { func SetLogConfig(cmd *exec.Cmd, t model.Task) error {
fLog, err := os.Create(path) //fLog, err := os.Create(path)
//if err != nil {
// log.Errorf("create task log file error: %s", path)
// debug.PrintStack()
// return err
//}
//cmd.Stdout = fLog
//cmd.Stderr = fLog
// get stdout reader
stdout, err := cmd.StdoutPipe()
readerStdout := bufio.NewReader(stdout)
if err != nil { if err != nil {
log.Errorf("create task log file error: %s", path) log.Errorf("get stdout error: %s", err.Error())
debug.PrintStack() debug.PrintStack()
return err return err
} }
cmd.Stdout = fLog
cmd.Stderr = fLog // get stderr reader
stderr, err := cmd.StderrPipe()
readerStderr := bufio.NewReader(stderr)
if err != nil {
log.Errorf("get stdout error: %s", err.Error())
debug.PrintStack()
return err
}
// read stdout
go func() {
for {
line, err := readerStdout.ReadString('\n')
if err != nil {
break
}
line = strings.Replace(line, "\n", "", -1)
_ = model.AddLogItem(model.LogItem{
Id: bson.NewObjectId(),
Message: line,
TaskId: t.Id,
IsError: false,
Ts: time.Now(),
})
}
}()
// read stderr
go func() {
for {
line, err := readerStderr.ReadString('\n')
line = strings.Replace(line, "\n", "", -1)
if err != nil {
break
}
_ = model.AddLogItem(model.LogItem{
Id: bson.NewObjectId(),
Message: line,
TaskId: t.Id,
IsError: true,
Ts: time.Now(),
})
}
}()
return nil return nil
} }
@@ -260,7 +316,7 @@ func ExecuteShellCmd(cmdStr string, cwd string, t model.Task, s model.Spider) (e
cmd.Dir = cwd cmd.Dir = cwd
// 日志配置 // 日志配置
if err := SetLogConfig(cmd, t.LogPath); err != nil { if err := SetLogConfig(cmd, t); err != nil {
return err return err
} }
@@ -566,54 +622,60 @@ func SpiderFileCheck(t model.Task, spider model.Spider) error {
return nil return nil
} }
func GetTaskLog(id string) (logStr string, err error) { func GetTaskLog(id string) (logItems []model.LogItem, err error) {
task, err := model.GetTask(id) task, err := model.GetTask(id)
if err != nil { if err != nil {
return return
} }
if IsMasterNode(task.NodeId.Hex()) { logItems, err = task.GetLogItems()
if !utils.Exists(task.LogPath) {
fileDir, err := MakeLogDir(task)
if err != nil {
log.Errorf(err.Error())
}
fileP := GetLogFilePaths(fileDir, task)
// 获取日志文件路径
fLog, err := os.Create(fileP)
defer fLog.Close()
if err != nil {
log.Errorf("create task log file error: %s", fileP)
debug.PrintStack()
}
task.LogPath = fileP
if err := task.Save(); err != nil {
log.Errorf(err.Error())
debug.PrintStack()
}
}
// 若为主节点,获取本机日志
logBytes, err := model.GetLocalLog(task.LogPath)
if err != nil {
log.Errorf(err.Error())
logStr = err.Error()
} else {
logStr = utils.BytesToString(logBytes)
}
return logStr, err
}
// 若不为主节点,获取远端日志
logStr, err = GetRemoteLog(task)
if err != nil { if err != nil {
log.Errorf(err.Error()) return logItems, err
} }
return logStr, err
return logItems, nil
//if IsMasterNode(task.NodeId.Hex()) {
// if !utils.Exists(task.LogPath) {
// fileDir, err := MakeLogDir(task)
//
// if err != nil {
// log.Errorf(err.Error())
// }
//
// fileP := GetLogFilePaths(fileDir, task)
//
// // 获取日志文件路径
// fLog, err := os.Create(fileP)
// defer fLog.Close()
// if err != nil {
// log.Errorf("create task log file error: %s", fileP)
// debug.PrintStack()
// }
// task.LogPath = fileP
// if err := task.Save(); err != nil {
// log.Errorf(err.Error())
// debug.PrintStack()
// }
//
// }
// // 若为主节点,获取本机日志
// logBytes, err := model.GetLocalLog(task.LogPath)
// if err != nil {
// log.Errorf(err.Error())
// logStr = err.Error()
// } else {
// logStr = utils.BytesToString(logBytes)
// }
// return logStr, err
//}
//// 若不为主节点,获取远端日志
//logStr, err = GetRemoteLog(task)
//if err != nil {
// log.Errorf(err.Error())
//
//}
//return logStr, err
} }
func CancelTask(id string) (err error) { func CancelTask(id string) (err error) {

View File

@@ -8,7 +8,7 @@ metadata:
spec: spec:
storageClassName: manual storageClassName: manual
capacity: capacity:
storage: 10Gi storage: 3Gi
accessModes: accessModes:
- ReadWriteOnce - ReadWriteOnce
hostPath: hostPath:
@@ -25,4 +25,4 @@ spec:
- ReadWriteOnce - ReadWriteOnce
resources: resources:
requests: requests:
storage: 10Gi storage: 3Gi

View File

@@ -20,6 +20,12 @@ export default {
type: Number, type: Number,
default: 1 default: 1
}, },
logItem: {
type: Object,
default () {
return {}
}
},
data: { data: {
type: String, type: String,
default: '' default: ''

View File

@@ -158,6 +158,7 @@ export default {
// https://vuejs.org/v2/guide/render-function.html#createElement-Arguments // https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
props: { props: {
index: logItem.index, index: logItem.index,
logItem,
data: isAnsi ? convert.toHtml(logItem.data) : logItem.data, data: isAnsi ? convert.toHtml(logItem.data) : logItem.data,
searchString: this.searchString, searchString: this.searchString,
active: logItem.active, active: logItem.active,

View File

@@ -6,7 +6,7 @@ const state = {
taskList: [], taskList: [],
taskListTotalCount: 0, taskListTotalCount: 0,
taskForm: {}, taskForm: {},
taskLog: '', taskLog: [],
currentLogIndex: 0, currentLogIndex: 0,
taskResultsData: [], taskResultsData: [],
taskResultsColumns: [], taskResultsColumns: [],
@@ -41,12 +41,13 @@ const getters = {
return keys return keys
}, },
logData (state) { logData (state) {
const data = state.taskLog.split('\n') const data = state.taskLog
.map((d, i) => { .map((d, i) => {
return { return {
index: i + 1, index: i + 1,
data: d, active: state.currentLogIndex === i + 1,
active: state.currentLogIndex === i + 1 data: d.msg,
...d
} }
}) })
if (state.taskForm && state.taskForm.status === 'running') { if (state.taskForm && state.taskForm.status === 'running') {
@@ -151,7 +152,7 @@ const actions = {
getTaskLog ({ state, commit }, id) { getTaskLog ({ state, commit }, id) {
return request.get(`/tasks/${id}/log`) return request.get(`/tasks/${id}/log`)
.then(response => { .then(response => {
commit('SET_TASK_LOG', response.data.data) commit('SET_TASK_LOG', response.data.data || [])
}) })
}, },
getTaskResults ({ state, commit }, id) { getTaskResults ({ state, commit }, id) {