我有不少行日誌數據單行的格式是這樣的nginx
HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=網頁瀏覽(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1310909;event_name=Microsoft_IIS_5.1_Frontpage擴展路徑信息漏洞;event_type=安全漏洞;level=info;ctime=2019-12-26 11:17:17;action=pass
其中ips:
以前的都是不規範的字段golang
我須要把他解析成結構化的數據,這樣的json
type IpsItem struct { UserId int `json:"user_id"` UserName string `json:"user_name"` SrcIp string `json:"src_ip"` DstIp string `json:"dst_ip"` SrcPort int `json:"src_port"` DstPort int `json:"dst_port"` AppName string `json:"app_name"` Protocol string `json:"protocol"` AppProtocol string `json:"app_protocol"` EventId int `json:"event_id"` EventName string `json:"event_name"` EventType string `json:"event_type"` Level string `json:"level"` Ctime string `json:"ctime"` Action string `json:"action"` }
若是上面日誌文件是json就很是容易解決了. 由於golang 標準庫使用的就是 reflect反射生成struct
.安全
因此個人思路也是使用reflect
反射實現字符串轉換成結構化的數據,你也能夠大體瞭解標準庫json.Unmarshal的原理.app
package main import ( "fmt" "reflect" "strings" ) var testRawString = "HOST;000012000629948340196501;ipv4;3; ips: user_id=2;user_name=172.21.1.102;policy_id=1;src_mac=52:54:00:62:7f:4a;dst_mac=58:69:6c:7b:fa:e7;src_ip=172.21.1.102;dst_ip=172.22.2.3;src_port=48612;dst_port=80;app_name=網頁瀏覽(HTTP);protocol=TCP;app_protocol=HTTP;event_id=1311495;event_name=HTTP_Nikto_WEB漏洞掃描;event_type=安全掃描;level=warning;ctime=2019-12-26 11:17:17;action=pass" type IpsItem struct { UserId int `json:"user_id"` UserName string `json:"user_name"` SrcIp string `json:"src_ip"` DstIp string `json:"dst_ip"` SrcPort int `json:"src_port"` DstPort int `json:"dst_port"` AppName string `json:"app_name"` Protocol string `json:"protocol"` AppProtocol string `json:"app_protocol"` EventId int `json:"event_id"` EventName string `json:"event_name"` EventType string `json:"event_type"` Level string `json:"level"` Ctime string `json:"ctime"` Action string `json:"action"` } func NewIpsItem(raw string) *IpsItem { //清除非法的字符 raw = strings.ReplaceAll(raw, ":", ";") ins := IpsItem{} t := reflect.TypeOf(ins) //遍歷結構體屬性 for i := 0; i < t.NumField(); i++ { //獲取屬性structField sf := t.Field(i) //屬性名稱 fieldName := sf.Name //tag json的值 tagName := sf.Tag.Get("json") //獲取字段值 fieldValue := reflect.ValueOf(&ins).Elem().FieldByName(fieldName) //屬性的值 type switch sf.Type.Name() { case "int": var someInt int64 scanValueFromString(raw, tagName, tagName+"=%d", &someInt) //給屬性賦值 fieldValue.SetInt(someInt) //todo:: 支持更多類型 default: var someString string scanValueFromString(raw, tagName, tagName+"=%s", &someString) ////給屬性賦值 fieldValue.SetString(someString) } } return &ins } //scanValueFromString 字符串 字段的值 func scanValueFromString(raw string, tagJsonValue, format string, someV interface{}) { for _, ss := range strings.Split(raw, ";") { ele := strings.TrimSpace(ss) if strings.HasPrefix(ele, tagJsonValue) { fmt.Sscanf(ele, format, someV) //n, err := fmt.Sscanf(ele, format, someV) //fmt.Println(n, err) return } } } func main() { ii := NewIpsItem(testRawString) fmt.Printf("%+v\n", ii) }