@@ -9,39 +9,41 @@ import (
9
9
10
10
//UserTraffic is a single decoded user traffic log line
11
11
type UserTraffic struct {
12
- Status int `json:"status"`
13
- RequestSize int64 `json:"request_size"`
14
- ResponseSize int64 `json:"response_size"`
15
- Timing int64 `json:"timing"`
16
- Timestamp time.Time `json:"timestamp"`
17
- RequestID string `json:"request_id"`
18
- Result string `json:"result"`
19
- CSID string `json:"csid"`
20
- CCID string `jsond:"ccid"`
21
- CID string `json:"cid"`
22
- Proto string `json:"proto"`
23
- Method string `json:"method"`
24
- URL string `json:"url"`
25
- SID string `json:"sid"`
26
- AID string `json:"aid"`
27
- DID string `json:"did"`
28
- Cancel string `json:"cancel"`
29
- CCancel string `json:"ccancel"`
30
- ProxyType string `json:"proxy_type"`
31
- FID string `json:"fid"`
32
- ContentType string `json:"content_type"`
33
- Address string `json:"address"`
34
- Country string `json:"country"`
35
- Referrer string `json:"referrer"`
36
- CW string `json:"cw"`
37
- SSLVersion string `json:"ssl_version"`
38
- SSLCipher string `json:"ssl_cipher"`
39
- ENC string `json:"enc"`
40
- UserAgent string `json:"ua"`
41
- Other map [ string ]string `json:"other "`
12
+ Status int `json:"status"`
13
+ RequestSize int64 `json:"request_size"`
14
+ ResponseSize int64 `json:"response_size"`
15
+ Timing int64 `json:"timing"`
16
+ Timestamp time.Time `json:"timestamp"`
17
+ RequestID string `json:"request_id"`
18
+ Result string `json:"result"`
19
+ CSID string `json:"csid"`
20
+ CCID string `jsond:"ccid"`
21
+ CID string `json:"cid"`
22
+ Proto string `json:"proto"`
23
+ Method string `json:"method"`
24
+ URL string `json:"url"`
25
+ SID string `json:"sid"`
26
+ AID string `json:"aid"`
27
+ DID string `json:"did"`
28
+ Cancel string `json:"cancel"`
29
+ CCancel string `json:"ccancel"`
30
+ ProxyType string `json:"proxy_type"`
31
+ FID string `json:"fid"`
32
+ ContentType string `json:"content_type"`
33
+ Address string `json:"address"`
34
+ Country string `json:"country"`
35
+ Referrer string `json:"referrer"`
36
+ CW string `json:"cw"`
37
+ SSLVersion string `json:"ssl_version"`
38
+ SSLCipher string `json:"ssl_cipher"`
39
+ ENC string `json:"enc"`
40
+ UserAgent string `json:"ua"`
41
+ Unparsed [ ]string `json:"unparsed "`
42
42
}
43
43
44
44
//ParseUserTrafficRecord parses a raw user traffic log line into a UserTraffic struct
45
+ //A slice of any unknown kv pairs or unbalanced fields will be appended to the UserTraffic
46
+ //structs Unparsed field.
45
47
func ParseUserTrafficRecord (raw string ) (* UserTraffic , error ) {
46
48
var ut UserTraffic
47
49
var err error
@@ -58,13 +60,14 @@ func ParseUserTrafficRecord(raw string) (*UserTraffic, error) {
58
60
59
61
for _ , field := range strings .Fields (praw [0 ]) {
60
62
parts := strings .SplitN (field , "=" , 2 )
61
- if len (parts ) != 2 {
62
- return nil , fmt .Errorf ("found key field with no value: %s" , parts )
63
+ if len (parts ) != 2 { // most commonly due to kv's with duplicate value fields
64
+ ut .Unparsed = append (ut .Unparsed , field )
65
+ continue
63
66
}
64
67
switch parts [0 ] {
65
68
case "request_id" :
66
69
ut .RequestID = parts [1 ]
67
- case "@timestamp" :
70
+ case "@timestamp" , "timestamp" :
68
71
tsFloat , err := strconv .ParseFloat (parts [1 ], 64 )
69
72
if err != nil {
70
73
return nil , fmt .Errorf ("malformed field (%s) value: %s" , parts [0 ], parts [1 ])
@@ -77,11 +80,11 @@ func ParseUserTrafficRecord(raw string) (*UserTraffic, error) {
77
80
case "result" :
78
81
ut .Result = parts [1 ]
79
82
case "csid" :
80
- ut .CSID = parts [1 ]
83
+ ut .CSID = strings . TrimSuffix ( parts [1 ], "," )
81
84
case "cid" :
82
- ut .CID = parts [1 ]
85
+ ut .CID = strings . TrimSuffix ( parts [1 ], "," )
83
86
case "ccid" :
84
- ut .CCID = parts [1 ]
87
+ ut .CCID = strings . TrimSuffix ( parts [1 ], "," )
85
88
case "status" :
86
89
if ut .Status , err = strconv .Atoi (parts [1 ]); err != nil {
87
90
return nil , fmt .Errorf ("malformed field (%s) value: %s" , parts [0 ], parts [1 ])
@@ -111,34 +114,31 @@ func ParseUserTrafficRecord(raw string) (*UserTraffic, error) {
111
114
//proactively handle
112
115
ut .AID = strings .TrimSuffix (parts [1 ], "," )
113
116
case "did" :
114
- ut .DID = parts [1 ]
117
+ ut .DID = strings . TrimSuffix ( parts [1 ], "," )
115
118
case "cancel" :
116
- ut .Cancel = parts [1 ]
119
+ ut .Cancel = strings . TrimSuffix ( parts [1 ], "," )
117
120
case "proxy_type" :
118
- ut .ProxyType = parts [1 ]
121
+ ut .ProxyType = strings . TrimSuffix ( parts [1 ], "," )
119
122
case "fid" :
120
- ut .FID = parts [1 ]
123
+ ut .FID = strings . TrimSuffix ( parts [1 ], "," )
121
124
case "content_type" :
122
- ut .ContentType = parts [1 ]
125
+ ut .ContentType = strings . TrimSuffix ( parts [1 ], "," )
123
126
case "address" :
124
- ut .Address = parts [1 ]
127
+ ut .Address = strings . TrimSuffix ( parts [1 ], "," )
125
128
case "country" :
126
- ut .Country = parts [1 ]
129
+ ut .Country = strings . TrimSuffix ( parts [1 ], "," )
127
130
case "referrer" :
128
- ut .Referrer = parts [1 ]
131
+ ut .Referrer = strings . TrimSuffix ( parts [1 ], "," )
129
132
case "cw" :
130
- ut .CW = parts [1 ]
133
+ ut .CW = strings . TrimSuffix ( parts [1 ], "," )
131
134
case "ssl_version" :
132
- ut .SSLVersion = parts [1 ]
135
+ ut .SSLVersion = strings . TrimSuffix ( parts [1 ], "," )
133
136
case "ssl_cipher" :
134
- ut .SSLCipher = parts [1 ]
137
+ ut .SSLCipher = strings . TrimSuffix ( parts [1 ], "," )
135
138
case "enc" :
136
- ut .ENC = parts [1 ]
139
+ ut .ENC = strings . TrimSuffix ( parts [1 ], "," )
137
140
default :
138
- if ut .Other == nil {
139
- ut .Other = make (map [string ]string )
140
- }
141
- ut .Other [parts [0 ]] = parts [1 ]
141
+ ut .Unparsed = append (ut .Unparsed , field )
142
142
}
143
143
}
144
144
return & ut , nil
0 commit comments