package service import ( "bufio" "errors" "fmt" "github.com/spf13/cast" "github.com/tealeg/xlsx" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/tools" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/constant" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/util" "os" "sort" "strconv" "strings" "time" "go.uber.org/zap" ) type LogManagement struct { User entity.SystemUserInfo } func (s *LogManagement) GetSysLogDir(search string) ([]string, error) { file, err := os.Open(conf.Options.LogDirPrefix) if err != nil { zap.L().Error("open file err:", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } names, err := file.Readdirnames(0) if err != nil { zap.L().Error("read dirnames err:", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } if search != "" { var filterdNames []string for i := range names { if strings.Index(names[i], search) >= 0 { filterdNames = append(filterdNames, names[i]) } } sort.Slice(filterdNames, func(i, j int) bool { st := strings.Index(filterdNames[i], "-") ed := strings.Index(filterdNames[i], ".") di, _ := time.Parse("2006-01-02", filterdNames[i][st+1:ed]) dj, _ := time.Parse("2006-01-02", filterdNames[j][st+1:ed]) return di.After(dj) }) return filterdNames, nil } sort.Slice(names, func(i, j int) bool { st := strings.Index(names[i], "-") ed := strings.Index(names[i], ".") di, _ := time.Parse("2006-01-02", names[i][st+1:ed]) dj, _ := time.Parse("2006-01-02", names[j][st+1:ed]) return di.After(dj) }) return names, nil } func (s *LogManagement) GetSysLog(logLevel, search, logName string) ([]string, error) { log, err := os.Open(conf.Options.LogDirPrefix + "/" + logName) if err != nil { zap.L().Error("open file err", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } var logArr []string reader := bufio.NewReader(log) for { rawLine, _, _ := reader.ReadLine() if len(rawLine) == 0 { break } flag1, flag2 := true, true line := string(rawLine) if search != "" { if strings.Index(line, search) < 0 { flag1 = false } } if logLevel != "" { if strings.Index(line, fmt.Sprintf(`"level":"%s"`, strings.ToUpper(logLevel))) < 0 { flag2 = false } } if flag1 && flag2 { logArr = append(logArr, line) } } return logArr, nil } // 用户行为审计列表 func (s *LogManagement) LogUserBehaviorList(params *request.LogUserBehaviorListReq) (list []response.SystemUserBehaviorList, total int64, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.ErrorDetail(err) return nil, 0, err } modelObj := db.Table("system_user_behavior").Alias("sub") modelObj.Join("INNER", []string{"system_user", "su"}, "sub.user_id = su.id") modelObj.Join("INNER", []string{"system_organization_tree", "sot"}, "sot.organization_id = su.organization_id") modelObj.Select("sub.*, su.system_account, su.phone, sot.name as org_name") // 条件查询 if params.Search != "" { keyword := util.SpecialEscape(params.Search) modelObj.Where("system_account like ? or system_module like ? or operate_addr like ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%") } // 上次访问时间 if params.StartAt != "" && params.EndAt != "" { applyEndTime, timeErr := time.Parse(jsontime.LocalDateFormat, params.EndAt) if timeErr != nil { conf.Logger.Error("时间转换错误", zap.Error(timeErr)) return nil, 0, resp.DbSelectError.ErrorDetail(timeErr) } EndAt := applyEndTime.AddDate(0, 0, 1).Format(jsontime.LocalDateFormat) modelObj.Where("last_access_time >= ? and last_access_time < ?", params.StartAt, EndAt) } // 操作类型 if params.OperateType != "" { modelObj.Where("operate_type = ?", params.OperateType) } // 请求方式 if params.ReqMethod != 0 { modelObj.Where("req_method = ?", params.ReqMethod) } // 操作状态 if params.OperateStatus != 0 { modelObj.Where("operate_status = ?", params.OperateStatus) } total, err = modelObj.OrderBy("created_time desc").Limit(params.GetPageSize(), params.GetOffset()).FindAndCount(&list) if err != nil { conf.Logger.Error("查询用户行为审计列表失败", zap.Error(err)) err = resp.DbSelectError.WithError(errors.New("查询用户行为审计列表失败")) return nil, 0, err } return list, total, nil } // 用户行为审计导出 func (s *LogManagement) LogUserBehaviorListExport(params *request.LogUserBehaviorListReq) (xlFile *xlsx.File, fileName string, err error) { xlFile = xlsx.NewFile() sheet, err := xlFile.AddSheet("sheet") if err != nil { return nil, "", resp.AddSheetError.ErrorDetail(err) } titleRow := sheet.AddRow() tmp := []string{ "序号", "账号", "手机号", "所属组织", "系统模块", "操作类型", "请求方式", "操作状态", "操作地址", "操作地点", "请求地址", "请求参数", "操作方法", "返回参数", "操作时间", } xlsRow2 := tools.NewRow(titleRow, tmp) err = xlsRow2.SetRowTitle() if err != nil { return } var ( list []response.SystemUserBehaviorList total int64 ) list, total, err = s.LogUserBehaviorList(params) if err != nil { return nil, "", resp.DbSelectError.ErrorDetail(err) } if total == 0 { return nil, "", resp.DbSelectError.ErrorDetail(errors.New("没有可导出的数据")) } fileName = "用户行为审计" + ".xlsx" id := 0 for _, detail := range list { id += 1 currentRow := sheet.AddRow() var tmp = []string{ strconv.Itoa(id), detail.SystemAccount, detail.Phone, detail.OrgName, detail.SystemModule, detail.OperateType, constant.HttpMethodStrMap[detail.ReqMethod], constant.OperateStatusStrMap[detail.OperateStatus], detail.OperateIp, detail.OperateAddr, detail.ReqUrl, detail.ReqParam, constant.HttpMethodStrMap[detail.ReqMethod], detail.ResFields, cast.ToString(detail.CreatedTime), } newRow := tools.NewRow(currentRow, tmp) err := newRow.GenerateRow() if err != nil { return nil, "", resp.AddSheetError.ErrorDetail(err) } } return } // 用户行为审计详情 func (s *LogManagement) LogUserBehaviorDetail(id string) (data *response.LogUserBehaviorDetailRep, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.ErrorDetail(err) return nil, err } data = new(response.LogUserBehaviorDetailRep) modelObj := db.Table("system_user_behavior").Alias("sub") modelObj.Join("INNER", []string{"system_user", "su"}, "sub.user_id = su.id") modelObj.Join("INNER", []string{"system_organization_tree", "sot"}, "sot.organization_id = su.organization_id") modelObj.Select("sub.*, su.system_account, su.phone, sot.name as org_name") _, err = modelObj.Where("sub.id = ?", id).And("sub.is_deleted = 0").Get(data) if err != nil { conf.Logger.Error("获取用户行为审计详情失败", zap.Error(err)) return nil, resp.DbSelectError.ErrorDetail(err) } data.OperateStatusStr = constant.OperateStatusStrMap[data.OperateStatus] data.ReqMethodStr = constant.HttpMethodStrMap[data.ReqMethod] //data.UserType = constant.UserTypeStrMap[data.IsAdmin] return data, nil } func (s *LogManagement) LogUserBehaviorDelete(ids []string) (err error) { db, err := client.GetDbClient() if err != nil { return resp.DbConnectError.ErrorDetail(err) } _, err = db.Table("system_user_behavior").In("id", ids).Update(&map[string]interface{}{"is_deleted": 1}) if err != nil { return resp.DbDeleteError.ErrorDetail(err) } return nil } //// LogUserAccountAuditList 行为日志列表 //func (s *LogManagement) LogUserAccountAuditList(params *request.LogManagementListReq) ([]response.LogManagementRep, int64, error) { // var logManagementRep = []response.LogManagementRep{} // db, err := client.GetDbClient() // if err != nil { // err = res.DbConnectError.ErrorDetail(err) // return nil, 0, err // } // // modelObj := db.Table("system_user as u") // modelObj.Join("left", "system_organization as org", "u.organization_id = org.organization_id"). // Select(`u.ID, // system_account, // contact_phone, // case is_admin when 1 then '业务系统账号' when 2 then '组织管理员账号' when 3 then '平台用户账号' when 4 then '超级管理员' end as is_admin, // NAME, // u.organization_id, // last_access_time, // case pwd_level when 1 then '弱' when 2 then '中' when 3 then '强' end as pwd_level, // pwd_updated_time, // date_part('day', now()-pwd_updated_time)as pwd_is_used , // u.created_time `) // // // 条件查询 // if params.Search != "" { // keyword := util.SpecialEscape(params.Search) // modelObj.Where("system_account ilike ? or contact_phone ilike ? or NAME ilike ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%") // } // // 用户类型 // if params.IsAdmin != 0 { // modelObj.Where("is_admin = ?", params.IsAdmin) // } // // 上次访问时间 // if params.StartAt != "" && params.EndAt != "" { // applyEndTime, timeErr := time.Parse(jsonTime.LocalDateFormat, params.EndAt) // if timeErr != nil { // conf.Logger.Error("时间转换错误", zap.Error(timeErr)) // return nil, 0, res.DataFailError.ErrorDetail(timeErr) // } // EndAt := applyEndTime.AddDate(0, 0, 1).Format(jsonTime.LocalDateFormat) // modelObj.Where("last_access_time >= ? and last_access_time < ?", params.StartAt, EndAt) // } // // 活跃度 1: 低 2:中 3: 高 // if params.Active != 0 { // switch params.Active { // case 1: // modelObj.Where("last_access_time <= now()-interval '1 month'") // case 2: // modelObj.Where("last_access_time < now()-interval '1 week'").And("last_access_time > now()-interval '1 month'") // case 3: // modelObj.Where("last_access_time >= now()-interval '1 week'") // } // } // // 密码强度 // if params.PwdLevel != 0 { // modelObj.Where("pwd_level = ? ", params.PwdLevel) // } // count, err := modelObj.OrderBy("last_access_time desc").Limit(int(params.Limit), int(params.Offset)).FindAndCount(&logManagementRep) // if err != nil { // conf.Logger.Error("查询用户账户审计列表失败", zap.Error(err)) // err = res.DbSelectError.ErrorDetail(errors.New("查询用户账户审计列表失败")) // return nil, 0, err // } // for k := range logManagementRep { // // lastAccessTime := cast.ToTime(logManagementRep[k].LastAccessTimes) // active := getActivity(logManagementRep[k].LastAccessTimes) // logManagementRep[k].Active = active // logManagementRep[k].LastAccessTime = jsonTime.JsonTime(logManagementRep[k].LastAccessTimes) // } // // return logManagementRep, count, nil //} // //func getActivity(date time.Time) string { // // dates := cast.ToTime(date) // var ( // lastAccess = date.Unix() // pastWeek = time.Now().AddDate(0, 0, -7).Unix() // pastMonth = time.Now().AddDate(0, -1, 0).Unix() // ) // if lastAccess >= pastWeek { // return "高" // } // if lastAccess < pastWeek && lastAccess > pastMonth { // return "中" // } // if lastAccess <= pastMonth { // return "低" // } // return "不活跃" //} // //// LogUserAccountAuditExport 行为日志导出 //func (s *LogManagement) LogUserAccountAuditExport(params *request.LogManagementListReq) (xlFile *xlsx.File, fileName string, err error) { // xlFile = xlsx.NewFile() // sheet, err := xlFile.AddSheet("sheet") // if err != nil { // conf.Logger.Error("xlFile.AddSheet err", zap.Error(err)) // return // } // titleRow := sheet.AddRow() // tmp := []string{ // "序号", "账号", "手机号", "用户类型", "所属组织", "上次访问时间", "活跃度", "密码强度", "密码使用时长/天", "创建时间", // } // xlsRow2 := tools.NewRow(titleRow, tmp) // err = xlsRow2.SetRowTitle() // if err != nil { // return // } // params.Page = 0 // params.Limit = 20000 // list, total, err := s.LogUserAccountAuditList(params) // if total == 0 { // err = errors.New("没有可导出的数据") // return // } else { // fileName = "用户账号审计" + ".xlsx" // } // id := 0 // for _, detail := range list { // id += 1 // currentRow := sheet.AddRow() // var tmp = []string{ // strconv.Itoa(id), detail.SystemAccount, detail.ContactPhone, detail.IsAdmin, detail.Name, cast.ToString(detail.LastAccessTime), // detail.Active, detail.PwdLevel, strconv.Itoa(detail.PwdIsUsed), cast.ToString(detail.CreatedTime), // } // newRow := tools.NewRow(currentRow, tmp) // err := newRow.GenerateRow() // if err != nil { // return nil, "", err // } // } // return //} // //// 用户行为审计列表 //func (s *LogManagement) LogUserBehaviorListEs(params *request.LogUserBehaviorListReq) (list []response.SystemUserBehaviorList, total int64, err error) { // es, err := client.GetEsConnection(conf.EsDoc.Index) // if err != nil { // return nil, 0, res.DbConnectError.ErrorDetail(err) // } // // boolQuery 可用于组合查询 // boolQuery := elastic.NewBoolQuery() // // 条件查询 // if params.Search != "" { // keyword := util.SpecialEscape(params.Search) // boolQuery.Filter( // elastic.NewBoolQuery().Should( // elastic.NewWildcardQuery("system_account.keyword", fmt.Sprintf("*%s*", keyword)), // elastic.NewWildcardQuery("system_module.keyword", fmt.Sprintf("*%s*", keyword)), // elastic.NewWildcardQuery("operate_addr.keyword", fmt.Sprintf("*%s*", keyword)), // )) // } // // 用户类型 // if params.IsAdmin != 0 { // boolQuery.Filter(elastic.NewMatchQuery("is_admin", params.IsAdmin)) // } // // 上次访问时间 // if params.StartAt != "" && params.EndAt != "" { // applyEndTime, timeErr := time.Parse(jsonTime.LocalDateFormatEs, params.EndAt) // if timeErr != nil { // conf.Logger.Error("时间转换错误", zap.Error(timeErr)) // return nil, 0, res.DataFailError.ErrorDetail(timeErr) // } // EndAt := applyEndTime.AddDate(0, 0, 1).Format(jsonTime.LocalDateFormatEs) // boolQuery.Filter(elastic.NewRangeQuery("created_time").Gte(params.StartAt)) // boolQuery.Filter(elastic.NewRangeQuery("created_time").Lt(EndAt)) // } // // 操作类型 // if params.OperateType != "" { // boolQuery.Filter(elastic.NewMatchQuery("operate_type", params.OperateType)) // } // // 请求方式 // if params.ReqMethod != 0 { // boolQuery.Filter(elastic.NewMatchQuery("req_method", params.ReqMethod)) // } // // 操作状态 // if params.OperateStatus != 0 { // boolQuery.Filter(elastic.NewMatchQuery("operate_status", params.OperateStatus)) // } // searchResult, err := es.Conn.Search(). // Index(conf.EsDoc.Index). // Query(boolQuery). // SortWithInfo(elastic.SortInfo{Field: "created_time_unix", Ascending: false, UnmappedType: "keyword"}). // From(int((params.Page - 1) * params.Limit)).Size(cast.ToInt(params.Limit)). // Pretty(true). // Do(context.Background()) // if err != nil { // conf.Logger.Error("查询用户行为审计列表失败", zap.Error(err)) // return nil, 0, res.DbSelectError.ErrorDetail(err) // } // bytes, err := json.Marshal(searchResult) // if err != nil { // conf.Logger.Error("json.Marshal序列化用户行为信息失败", zap.Error(err)) // return nil, 0, res.JsonMarshalError.ErrorDetail(err) // } // resultMap := map[string]interface{}{} // err = json.Unmarshal(bytes, &resultMap) // if err != nil { // conf.Logger.Error("序列化用户行为信息失败", zap.Error(err)) // return nil, 0, res.JsonMarshalError.ErrorDetail(err) // } // data, has := resultMap["hits"] // esData := response.BehaviorEsListInfo{} // if has { // bytes, err := json.Marshal(data) // if err != nil { // conf.Logger.Error("序列化用户行为信息失败", zap.Error(err)) // return nil, 0, err // } // err = json.Unmarshal(bytes, &esData) // if err != nil { // conf.Logger.Error("序列化用户行为信息失败", zap.Error(err)) // return nil, 0, err // } // for k, v := range esData.Hits { // esData.Hits[k].Source.Id = v.Id // esData.Hits[k].Source.Xh = (params.Page) * int64(k+1) // list = append(list, esData.Hits[k].Source) // } // } // total = cast.ToInt64(esData.Total["value"]) // return list, total, nil //} //