package models import ( "github.com/TeaOSLab/EdgeAPI/internal/errors" "github.com/TeaOSLab/EdgeCommon/pkg/configutils" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" _ "github.com/go-sql-driver/mysql" "github.com/iwind/TeaGo/Tea" "github.com/iwind/TeaGo/dbs" "github.com/iwind/TeaGo/types" stringutil "github.com/iwind/TeaGo/utils/string" timeutil "github.com/iwind/TeaGo/utils/time" "strconv" "strings" "time" ) type NodeLogDAO dbs.DAO func NewNodeLogDAO() *NodeLogDAO { return dbs.NewDAO(&NodeLogDAO{ DAOObject: dbs.DAOObject{ DB: Tea.Env, Table: "edgeNodeLogs", Model: new(NodeLog), PkName: "id", }, }).(*NodeLogDAO) } var SharedNodeLogDAO *NodeLogDAO func init() { dbs.OnReady(func() { SharedNodeLogDAO = NewNodeLogDAO() }) } // CreateLog 创建日志 func (this *NodeLogDAO) CreateLog(tx *dbs.Tx, nodeRole nodeconfigs.NodeRole, nodeId int64, serverId int64, originId int64, level string, tag string, description string, createdAt int64) error { hash := stringutil.Md5(nodeRole + "@" + types.String(nodeId) + "@" + types.String(serverId) + "@" + types.String(originId) + "@" + level + "@" + tag + "@" + description) // 检查是否在重复最后一条,避免重复创建 lastLog, err := this.Query(tx). Result("id", "hash", "createdAt"). DescPk(). Find() if err != nil { return err } if lastLog != nil { nodeLog := lastLog.(*NodeLog) if nodeLog.Hash == hash && time.Now().Unix()-int64(nodeLog.CreatedAt) < 1800 { err = this.Query(tx). Pk(nodeLog.Id). Set("count", dbs.SQL("count+1")). UpdateQuickly() return err } } op := NewNodeLogOperator() op.Role = nodeRole op.NodeId = nodeId op.ServerId = serverId op.OriginId = originId op.Level = level op.Tag = tag op.Description = description op.CreatedAt = createdAt op.Day = timeutil.FormatTime("Ymd", createdAt) op.Hash = hash op.Count = 1 err = this.Save(tx, op) return err } // DeleteExpiredLogs 清除超出一定日期的日志 func (this *NodeLogDAO) DeleteExpiredLogs(tx *dbs.Tx, days int) error { if days <= 0 { return errors.New("invalid days '" + strconv.Itoa(days) + "'") } date := time.Now().AddDate(0, 0, -days) expireDay := timeutil.Format("Ymd", date) _, err := this.Query(tx). Where("day<=:day"). Param("day", expireDay). Delete() return err } // CountNodeLogs 计算节点日志数量 func (this *NodeLogDAO) CountNodeLogs(tx *dbs.Tx, role string, nodeId int64, serverId int64, originId int64, dayFrom string, dayTo string, keyword string, level string) (int64, error) { query := this.Query(tx). Attr("role", role) if nodeId > 0 { query.Attr("nodeId", nodeId) } else { switch role { case nodeconfigs.NodeRoleNode: query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)") case nodeconfigs.NodeRoleDNS: query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId > 0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题 } } if serverId > 0 { query.Attr("serverId", serverId) } if originId > 0 { query.Attr("originId", originId) } if len(dayFrom) > 0 { dayFrom = strings.ReplaceAll(dayFrom, "-", "") query.Gte("day", dayFrom) } if len(dayTo) > 0 { dayTo = strings.ReplaceAll(dayTo, "-", "") query.Lte("day", dayTo) } if len(keyword) > 0 { query.Where("(tag LIKE :keyword OR description LIKE :keyword)"). Param("keyword", "%"+keyword+"%") } if len(level) > 0 { query.Attr("level", level) } return query.Count() } // ListNodeLogs 列出单页日志 func (this *NodeLogDAO) ListNodeLogs(tx *dbs.Tx, role string, nodeId int64, serverId int64, originId int64, allServers bool, dayFrom string, dayTo string, keyword string, level string, fixedState configutils.BoolState, offset int64, size int64) (result []*NodeLog, err error) { query := this.Query(tx). Attr("role", role) if nodeId > 0 { query.Attr("nodeId", nodeId) } else { switch role { case nodeconfigs.NodeRoleNode: query.Where("nodeId IN (SELECT id FROM " + SharedNodeDAO.Table + " WHERE state=1 AND clusterId>0)") case nodeconfigs.NodeRoleDNS: query.Where("nodeId IN (SELECT id FROM edgeNSNodes WHERE state=1 AND clusterId>0)") // 没有用 SharedNSNodeDAO() 因为有包循环引用的问题 } } if serverId > 0 { query.Attr("serverId", serverId) } else if allServers { query.Where("serverId>0") } if originId > 0 { query.Attr("originId", originId) } if fixedState == configutils.BoolStateYes { query.Attr("isFixed", 1) } else if fixedState == configutils.BoolStateNo { query.Attr("isFixed", 0) } if len(dayFrom) > 0 { dayFrom = strings.ReplaceAll(dayFrom, "-", "") query.Gte("day", dayFrom) } if len(dayTo) > 0 { dayTo = strings.ReplaceAll(dayTo, "-", "") query.Lte("day", dayTo) } if len(keyword) > 0 { query.Where("(tag LIKE :keyword OR description LIKE :keyword)"). Param("keyword", "%"+keyword+"%") } if len(level) > 0 { query.Attr("level", level) } _, err = query. Offset(offset). Limit(size). Slice(&result). DescPk(). FindAll() return } // UpdateNodeLogFixed 设置节点日志为已修复 func (this *NodeLogDAO) UpdateNodeLogFixed(tx *dbs.Tx, logId int64) error { if logId <= 0 { return errors.New("invalid logId") } // 我们把相同内容的日志都置为已修复 hash, err := this.Query(tx). Pk(logId). Result("hash"). FindStringCol("") if err != nil { return err } if len(hash) == 0 { return nil } err = this.Query(tx). Attr("hash", hash). Attr("isFixed", false). Set("isFixed", true). UpdateQuickly() if err != nil { return err } return nil }