فهرست منبع

feat(waflog): 优化日志解析和导出功能

- 修改 RuleId 字段类型为 []int64,以支持多个规则 ID
- 添加 AllowAndDenyIps 字段用于记录黑白名单 IP
- 重构日志解析逻辑,提高灵活性和准确性
- 优化日志导出功能,支持新字段和格式化输出- 移除冗余代码,提高代码可维护性
fusu 3 روز پیش
والد
کامیت
d89a77e953
3فایلهای تغییر یافته به همراه137 افزوده شده و 41 حذف شده
  1. 2 1
      api/v1/admin/wafLog.go
  2. 21 39
      internal/service/admin/waflog.go
  3. 114 1
      internal/service/admin/waflogdataclean.go

+ 2 - 1
api/v1/admin/wafLog.go

@@ -57,9 +57,10 @@ type ExportWafLogRes struct {
 	Name       string `json:"name" form:"name"`
 	RequestIp  string `json:"requestIp" form:"requestIp"`
 	HostId     int    `json:"hostId" form:"hostId"`
-	RuleId     int    `json:"ruleId,omitempty" form:"ruleId" `
+	RuleId     []int64    `json:"ruleId,omitempty" form:"ruleId" `
 	ApiName    string `json:"apiName" form:"apiName"`
 	AddrBackendList  interface{} `json:"addrBackendList" form:"addrBackendList"`
+	AllowAndDenyIps  string `json:"allowAndDenyIps" form:"allowAndDenyIps"`
 	Domain     string `json:"domain" form:"domain"`
 	CustomHost []string `json:"customHost" form:"customHost"`
 	ExposeAddr  []string `json:"exposeAddr" form:"exposeAddr"`

+ 21 - 39
internal/service/admin/waflog.go

@@ -273,7 +273,7 @@ func (s *wafLogService) SmartExportWafLog(ctx context.Context, req adminApi.Expo
 	exportType := excel.SmartExport(count, 200)
 	
 	// 3. 设置Excel表头映射
-	headers := []string{"name", "request_ip", "host_id", "rule_id", "api_name", "addr_backend_list", "domain", "comment", "custom_host", "expose_addr", "created_at"}
+	headers := []string{"name", "request_ip", "host_id", "rule_id", "api_name", "addr_backend_list", "allow_and_deny_ips", "domain", "comment", "custom_host", "expose_addr", "created_at"}
 	headerMap := map[string]string{
 		"name":             "用户名",
 		"request_ip":       "请求IP",
@@ -281,6 +281,7 @@ func (s *wafLogService) SmartExportWafLog(ctx context.Context, req adminApi.Expo
 		"rule_id":          "规则ID",
 		"api_name":         "API名称",
 		"addr_backend_list": "后端地址",
+		"allow_and_deny_ips": "黑白名单",
 		"domain":           "域名",
 		"comment":          "备注",
 		"custom_host":      "回源地址",
@@ -322,13 +323,14 @@ func (s *wafLogService) normalExportWafLog(ctx context.Context, req adminApi.Exp
 			"name":             item.Name,
 			"request_ip":       item.RequestIp,
 			"host_id":          item.HostId,
-			"rule_id":          item.RuleId,
+			"rule_id":          s.wafLogDataCleanService.FormatBackendList(item.RuleId),
 			"api_name":         item.ApiName,
-			"addr_backend_list": s.formatBackendList(item.AddrBackendList),
+			"addr_backend_list": s.wafLogDataCleanService.FormatBackendList(item.AddrBackendList),
+			"allow_and_deny_ips": item.AllowAndDenyIps,
 			"domain":           item.Domain,
 			"comment":          item.Comment,
-			"custom_host":      s.formatExposeAddr(item.CustomHost),
-			"expose_addr":      s.formatExposeAddr(item.ExposeAddr),
+			"custom_host":     s.wafLogDataCleanService.FormatBackendList(item.CustomHost),
+			"expose_addr":      s.wafLogDataCleanService.FormatBackendList(item.ExposeAddr),
 			"created_at":       item.CreatedAt,
 		}
 		data = append(data, row)
@@ -383,12 +385,14 @@ func (s *wafLogService) streamExportWafLog(ctx context.Context, req adminApi.Exp
 				"name":             item.Name,
 				"request_ip":       item.RequestIp,
 				"host_id":          item.HostId,
+				"rule_id":          s.wafLogDataCleanService.FormatBackendList(item.RuleId),
 				"api_name":         item.ApiName,
-				"addr_backend_list": s.formatBackendList(item.AddrBackendList),
+				"addr_backend_list": s.wafLogDataCleanService.FormatBackendList(item.AddrBackendList),
+				"allow_and_deny_ips": item.AllowAndDenyIps,
 				"domain":           item.Domain,
 				"comment":          item.Comment,
-				"custom_host":      s.formatExposeAddr(item.CustomHost),
-				"expose_addr":      s.formatExposeAddr(item.ExposeAddr),
+				"custom_host":      s.wafLogDataCleanService.FormatBackendList(item.CustomHost),
+				"expose_addr":      s.wafLogDataCleanService.FormatBackendList(item.ExposeAddr),
 				"created_at":       item.CreatedAt,
 			}
 			
@@ -426,37 +430,7 @@ func (s *wafLogService) chunkExportWafLog(ctx context.Context, req adminApi.Expo
 	return nil
 }
 
-// formatBackendList 格式化后端地址列表
-func (s *wafLogService) formatBackendList(backendList interface{}) string {
-	if backendList == nil {
-		return ""
-	}
-	
-	switch v := backendList.(type) {
-	case string:
-		return v
-	case []string:
-		return strings.Join(v, ", ")
-	default:
-		// 对于其他类型,先转换为字符串再处理
-		str := fmt.Sprintf("%v", v)
-		if strings.Contains(str, " ") && !strings.Contains(str, "\n") {
-			parts := strings.Fields(str)
-			if len(parts) > 1 {
-				return strings.Join(parts, ",   ")
-			}
-		}
-		return str
-	}
-}
 
-// formatExposeAddr 格式化暴露地址
-func (s *wafLogService) formatExposeAddr(exposeAddr []string) string {
-	if len(exposeAddr) == 0 {
-		return ""
-	}
-	return strings.Join(exposeAddr, ", ")
-}
 
 
 
@@ -515,14 +489,22 @@ func (s *wafLogService) convertRawDataToExportResults(ctx context.Context, rawDa
 			}
 		}
 
+		var ruleIds []int64
+		if len(cleanedData.RuleID) > 0 {
+			ruleIds = cleanedData.RuleID
+		}else {
+			ruleIds = []int64{int64(v.RuleId)}
+		}
+
 		// 构造结果,代码更清晰
 		res = append(res, adminApi.ExportWafLogRes{
 			Name:            v.Name,
 			RequestIp:       v.RequestIp,
 			HostId:          v.HostId,
-			RuleId:          v.RuleId,
+			RuleId:          ruleIds,
 			ApiName:         v.ApiName,
 			AddrBackendList: cleanedData.AddrBackendList,
+			AllowAndDenyIps: cleanedData.AllowAndDenyIps,
 			Domain:          cleanedData.Domain,
 			Comment:         cleanedData.Comment,
 			CustomHost:      cleanedData.CustomHost,

+ 114 - 1
internal/service/admin/waflogdataclean.go

@@ -2,13 +2,16 @@ package admin
 
 import (
 	"encoding/json"
+	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/internal/service"
 	"github.com/tidwall/gjson"
 	"go.uber.org/zap"
+	"strings"
 )
 
 type WafLogDataCleanService interface {
 	ParseWafLogExtraData(extraDataBytes json.RawMessage, apiName string) CleanedExtraData
+	FormatBackendList(backendList interface{}) string
 }
 func NewWafLogDataCleanService(
     service *service.Service,
@@ -51,6 +54,10 @@ type CleanedExtraData struct {
 	HostID          int64    `json:"hostId,omitempty"`
 	Proxy           bool     `json:"proxy,omitempty"`
 	IsHttps         int      `json:"isHttps,omitempty"`
+	RuleID          []int64    `json:"ruleId,omitempty"`
+
+	// 其他字段
+	AllowAndDenyIps string   `json:"allowAndDenyIps,omitempty"`
 	
 	// 动态字段存储,用于存储任意其他字段
 	DynamicFields map[string]interface{} `json:"dynamicFields,omitempty"`
@@ -105,6 +112,8 @@ func (s *wafLogDataCleanService) extractWithGjson(jsonStr, apiName string, resul
 		"domain":  {"domain", "data.domain", "host", "data.host", "hostname"},
 		"proxy":   {"proxy", "data.proxy"},
 		"isHttps": {"isHttps", "data.isHttps"},
+		"ids":     {"ids", "data.ids", "ruleIds", "data.ruleIds", "ruleId", "data.ruleId"},
+		"ip":      {"ip","newIp","ips"},
 	}
 	
 	// 提取基础字段
@@ -122,6 +131,11 @@ func (s *wafLogDataCleanService) extractWithGjson(jsonStr, apiName string, resul
 				result.Proxy = gjson.Get(jsonStr, s.getFirstValidPathName(jsonStr, paths)).Bool()
 			case "isHttps":
 				result.IsHttps = int(gjson.Get(jsonStr, s.getFirstValidPathName(jsonStr, paths)).Int())
+			case "ids":
+				result.RuleID = s.extractRuleIDs(jsonStr, paths)
+			case "ip":
+				result.AllowAndDenyIps = value
+
 			}
 
 		}
@@ -154,11 +168,46 @@ func (s *wafLogDataCleanService) getFirstValidPathName(jsonStr string, paths []s
 	return ""
 }
 
+// extractRuleIDs 提取规则ID数组
+func (s *wafLogDataCleanService) extractRuleIDs(jsonStr string, paths []string) []int64 {
+	var ruleIDs []int64
+	
+	for _, path := range paths {
+		ruleResult := gjson.Get(jsonStr, path)
+		if !ruleResult.Exists() {
+			continue
+		}
+		
+		switch {
+		case ruleResult.IsArray():
+			// 如果是数组,遍历提取每个ID
+			ruleResult.ForEach(func(key, value gjson.Result) bool {
+				if id := value.Int(); id > 0 {
+					ruleIDs = append(ruleIDs, id)
+				}
+				return true
+			})
+		default:
+			// 如果是单个值,添加到数组中
+			if id := ruleResult.Int(); id > 0 {
+				ruleIDs = append(ruleIDs, id)
+			}
+		}
+		
+		// 找到有效数据就退出
+		if len(ruleIDs) > 0 {
+			break
+		}
+	}
+	
+	return ruleIDs
+}
+
 // extractBackendListWithGjson 使用gjson智能提取后端列表
 func (s *wafLogDataCleanService) extractBackendListWithGjson(jsonStr, apiName string, result *CleanedExtraData) {
 	// 定义可能的后端列表字段路径
 	backendPaths := []string{
-		"backendList", "data.backendList", "backends", "data.backends", 
+		"data.backendList", "backendList", "backends", "data.backends",
 		"backend_list", "data.backend_list", "servers", "data.servers",
 		"upstreams", "data.upstreams", "targets", "data.targets",
 	}
@@ -267,3 +316,67 @@ func (s *wafLogDataCleanService) extractDynamicFields(jsonStr string, result *Cl
 	}
 }
 
+
+
+// formatBackendList 格式化后端地址列表
+func (s *wafLogDataCleanService) FormatBackendList(backendList interface{}) string {
+	if backendList == nil {
+		return ""
+	}
+
+	switch v := backendList.(type) {
+	case string:
+		return v
+	case []string:
+		if len(v) == 0 {
+			return ""
+		}
+		return strings.Join(v, ", ")
+	case []int64:
+		// 处理 []int64 类型的数组(如 RuleId)
+		if len(v) == 0 {
+			return ""
+		}
+		var strList []string
+		for _, id := range v {
+			strList = append(strList, fmt.Sprintf("%d", id))
+		}
+		return strings.Join(strList, ", ")
+	case []interface{}:
+		// 处理 []interface{} 类型的数组
+		if len(v) == 0 {
+			return ""
+		}
+		var strList []string
+		for _, item := range v {
+			if str := fmt.Sprintf("%v", item); str != "" && str != "<nil>" {
+				strList = append(strList, str)
+			}
+		}
+		return strings.Join(strList, ", ")
+	default:
+		// 对于其他类型,先转换为字符串再处理
+		str := fmt.Sprintf("%v", v)
+		// 处理 Go 数组格式 [item1 item2] -> item1, item2
+		if strings.HasPrefix(str, "[") && strings.HasSuffix(str, "]") {
+			// 移除方括号
+			content := strings.Trim(str, "[]")
+			if content != "" {
+				// 按空格分割并用逗号连接
+				parts := strings.Fields(content)
+				if len(parts) > 1 {
+					return strings.Join(parts, ", ")
+				}
+				return content
+			}
+		}
+		// 处理其他包含空格的字符串
+		if strings.Contains(str, " ") && !strings.Contains(str, "\n") {
+			parts := strings.Fields(str)
+			if len(parts) > 1 {
+				return strings.Join(parts, ", ")
+			}
+		}
+		return str
+	}
+}