glogcenter/glc/www/controller/log_search_controller.go
2023-11-05 14:59:52 +08:00

153 lines
6.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controller
import (
"glc/com"
"glc/conf"
"glc/gweb"
"glc/ldb"
"glc/ldb/search"
"glc/ldb/sysmnt"
"time"
"github.com/gotoeasy/glang/cmn"
)
type storageItem struct {
storeName string // 日志仓
total uint32 // 日志件数
isSearchRange bool // 是否条件范围的日志仓
}
var cacheStoreNames []string // 所有的日志仓(避免每次读磁盘,适当使用缓存)
var cacheTime time.Time // 最近一次读日志仓目录的时间点
// 日志检索(表单提交方式)
func LogSearchController(req *gweb.HttpRequest) *gweb.HttpResult {
if !InWhiteList(req) && InBlackList(req) {
return gweb.Error403() // 黑名单,访问受限
}
if conf.IsEnableLogin() && req.GetFormParameter("token") != GetSessionid() {
return gweb.Error403() // 登录检查
}
startTime := time.Now()
cond := &search.SearchCondition{SearchSize: conf.GetPageSize()}
cond.StoreName = req.GetFormParameter("storeName") // 日志仓条件
cond.SearchKey = req.GetFormParameter("searchKey") // 输入的查询关键词
cond.CurrentStoreName = req.GetFormParameter("currentStoreName") // 滚动查询时定位用日志仓
cond.CurrentId = cmn.StringToUint32(req.GetFormParameter("currentId"), 0) // 滚动查询时定位用ID
cond.Forward = cmn.StringToBool(req.GetFormParameter("forward"), true) // 是否向下滚动查询
cond.DatetimeFrom = req.GetFormParameter("datetimeFrom") // 日期范围From
cond.DatetimeTo = req.GetFormParameter("datetimeTo") // 日期范围To
cond.System = req.GetFormParameter("system") // 系统
cond.Loglevel = req.GetFormParameter("loglevel") // 单选条件
cond.Loglevels = cmn.Split(cond.Loglevel, ",") // 多选条件
if len(cond.Loglevels) <= 1 || len(cond.Loglevels) >= 4 {
cond.Loglevels = make([]string, 0) // 多选的单选或全选都清空单选走loglevel索引全选等于没选
}
if !cmn.IsBlank(cond.System) {
cond.System = "~" + cmn.Trim(cond.System) // 编辑系统条件,以便精确匹配
}
if !cmn.IsBlank(cond.Loglevel) && !cmn.Contains(cond.Loglevel, ",") {
cond.Loglevel = "!" + cmn.Trim(cond.Loglevel) // 编辑日志级别单选条件,以便精确匹配
} else {
cond.Loglevel = "" // 清空日志级别单选条件以便多选配配改用loglevels
}
// 范围内的日志仓都查一遍
// 注1日志不断新增时总件数可能会因为时间点原因不适最新从而变现出点点小误差【完全可接受】
// 注2跨仓检索时非本次检索的目标仓的话只查取相关件数不做真正筛选计数以提高性能醉打匹配件数有时可能出现较大误差【折中可接受】
result := &search.SearchResult{PageSize: cmn.IntToString(conf.GetPageSize())}
var total uint32
var count uint32
storeItems := getStoreItems(cond.StoreName, cond.DatetimeFrom, cond.DatetimeTo)
sysmntStore := sysmnt.NewSysmntStorage()
for i, max := 0, len(storeItems); i < max; i++ {
item := storeItems[i]
if !item.isSearchRange {
// 不需要查数据,只查关联件数
total += sysmntStore.GetStorageDataCount(item.storeName) // 累加总件数
continue
}
cond.SearchSize = conf.GetPageSize() - len(result.Data) // 本次需要查多少件
if cond.CurrentStoreName != "" && item.storeName > cond.CurrentStoreName {
cond.SearchSize = 0 // 是范围内的日志仓但不是本次要查的设为0不查数据只查关联件数
}
eng := ldb.NewEngine(item.storeName) // 遍历日志仓检索
rs := eng.Search(cond) // 按动态的要求件数检索
total += cmn.StringToUint32(rs.Total, 0) // 累加总件数
count += cmn.StringToUint32(rs.Count, 0) // 累加最大匹配件数
if len(rs.Data) > 0 {
result.Data = append(result.Data, rs.Data...) // 累加查询结果
result.LastStoreName = item.storeName // 设定检索结果最后一条(最久远)日志所在的日志仓,页面向下滚动继续检索时定位用
}
if !(cond.CurrentStoreName != "" && item.storeName > cond.CurrentStoreName) {
// 仅针对更久远的日志仓
if len(result.Data) < conf.GetPageSize() && i < max-1 {
// 数据没查够,且后面还有日志仓待查询,准备好跨仓查询条件
cond.CurrentId = 0 // 下一日志仓从头开始查
cond.CurrentStoreName = "" // 从头开始所以这个条件不再适用,清空
}
}
}
result.Total = cmn.Uint32ToString(total) // 总件数
result.Count = cmn.Uint32ToString(count) // 最大匹配检索笼统在最大查取件数5000件内查完时前端会改成精确的和结果一样的件数
result.TimeMessage = "耗时" + cmn.GetTimeInfo(time.Since(startTime).Milliseconds()) // 查询耗时
return gweb.Result(result)
}
// 筛选出日志仓检索范围
func getStoreItems(storeName string, datetimeFrom string, datetimeTo string) []*storageItem {
sysmntStore := sysmnt.NewSysmntStorage()
var items []*storageItem
if !conf.IsStoreNameAutoAddDate() {
// 单日志仓
name := com.GeyStoreNameByDate("")
items = append(items, &storageItem{storeName: name, total: sysmntStore.GetStorageDataCount(name), isSearchRange: true})
return items
}
// 遍历日志仓,比较日期范围筛选日志仓
hasDateCond := (datetimeFrom != "" && datetimeTo != "") // 是否有日期范围条件
from := cmn.ReplaceAll(cmn.Left(datetimeFrom, 10), "-", "") // yyyymmdd或“”
to := cmn.ReplaceAll(cmn.Left(datetimeTo, 10), "-", "") // yyyymmdd或“”
if time.Since(cacheTime) >= time.Second*10 {
cacheStoreNames = com.GetStorageNames(conf.GetStorageRoot(), ".sysmnt") // 所有的日志仓结果已排序缓存10秒避免频繁读盘
cacheTime = time.Now()
}
for i, max := 0, len(cacheStoreNames); i < max; i++ {
name := cacheStoreNames[i]
item := &storageItem{storeName: name, total: sysmntStore.GetStorageDataCount(name)}
date := cmn.Right(name, 8) // yyyymmdd
if storeName == "" {
// 日志仓条件空白
if hasDateCond {
if date >= from && date <= to {
item.isSearchRange = true // 日期范围内的日志仓都是条件范围
}
} else {
item.isSearchRange = true // 无日志仓条件、且无日期条件,全部都是条件范围了
}
} else {
// 有日志仓条件
if hasDateCond {
if storeName == name && date >= from && date <= to {
item.isSearchRange = true // 有日期条件,得满足日期条件,该日志仓才是条件范围
}
} else {
if storeName == name {
item.isSearchRange = true // 没日期条件,仅该日志仓是条件范围
}
}
}
items = append(items, item)
}
return items
}