syslogparser.go (3717B)
1 package syslogparser 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "time" 8 ) 9 10 const ( 11 PRI_PART_START = '<' 12 PRI_PART_END = '>' 13 14 NO_VERSION = -1 15 ) 16 17 var ( 18 ErrEOL = &ParserError{"End of log line"} 19 ErrNoSpace = &ParserError{"No space found"} 20 21 ErrPriorityNoStart = &ParserError{"No start char found for priority"} 22 ErrPriorityEmpty = &ParserError{"Priority field empty"} 23 ErrPriorityNoEnd = &ParserError{"No end char found for priority"} 24 ErrPriorityTooShort = &ParserError{"Priority field too short"} 25 ErrPriorityTooLong = &ParserError{"Priority field too long"} 26 ErrPriorityNonDigit = &ParserError{"Non digit found in priority"} 27 28 ErrVersionNotFound = &ParserError{"Can not find version"} 29 30 ErrTimestampUnknownFormat = &ParserError{"Timestamp format unknown"} 31 32 ErrHostnameTooShort = &ParserError{"Hostname field too short"} 33 ) 34 35 type LogParser interface { 36 Parse() error 37 Dump() LogParts 38 Location(*time.Location) 39 } 40 41 type ParserError struct { 42 ErrorString string 43 } 44 45 type Priority struct { 46 P int 47 F Facility 48 S Severity 49 } 50 51 type Facility struct { 52 Value int 53 } 54 55 type Severity struct { 56 Value int 57 } 58 59 type LogParts map[string]interface{} 60 61 // https://tools.ietf.org/html/rfc3164#section-4.1 62 func ParsePriority(buff []byte, cursor *int, l int) (Priority, error) { 63 pri := newPriority(0) 64 65 if l <= 0 { 66 return pri, ErrPriorityEmpty 67 } 68 69 if buff[*cursor] != PRI_PART_START { 70 return pri, ErrPriorityNoStart 71 } 72 73 i := 1 74 priDigit := 0 75 76 for i < l { 77 if i >= 5 { 78 return pri, ErrPriorityTooLong 79 } 80 81 c := buff[i] 82 83 if c == PRI_PART_END { 84 if i == 1 { 85 return pri, ErrPriorityTooShort 86 } 87 88 *cursor = i + 1 89 return newPriority(priDigit), nil 90 } 91 92 if IsDigit(c) { 93 v, e := strconv.Atoi(string(c)) 94 if e != nil { 95 return pri, e 96 } 97 98 priDigit = (priDigit * 10) + v 99 } else { 100 return pri, ErrPriorityNonDigit 101 } 102 103 i++ 104 } 105 106 return pri, ErrPriorityNoEnd 107 } 108 109 // https://tools.ietf.org/html/rfc5424#section-6.2.2 110 func ParseVersion(buff []byte, cursor *int, l int) (int, error) { 111 if *cursor >= l { 112 return NO_VERSION, ErrVersionNotFound 113 } 114 115 c := buff[*cursor] 116 *cursor++ 117 118 // XXX : not a version, not an error though as RFC 3164 does not support it 119 if !IsDigit(c) { 120 return NO_VERSION, nil 121 } 122 123 v, e := strconv.Atoi(string(c)) 124 if e != nil { 125 *cursor-- 126 return NO_VERSION, e 127 } 128 129 return v, nil 130 } 131 132 func IsDigit(c byte) bool { 133 return c >= '0' && c <= '9' 134 } 135 136 func newPriority(p int) Priority { 137 // The Priority value is calculated by first multiplying the Facility 138 // number by 8 and then adding the numerical value of the Severity. 139 140 return Priority{ 141 P: p, 142 F: Facility{Value: p / 8}, 143 S: Severity{Value: p % 8}, 144 } 145 } 146 147 func FindNextSpace(buff []byte, from int, l int) (int, error) { 148 var to int 149 150 for to = from; to < l; to++ { 151 if buff[to] == ' ' { 152 to++ 153 return to, nil 154 } 155 } 156 157 return 0, ErrNoSpace 158 } 159 160 func Parse2Digits(buff []byte, cursor *int, l int, min int, max int, e error) (int, error) { 161 digitLen := 2 162 163 if *cursor+digitLen > l { 164 return 0, ErrEOL 165 } 166 167 sub := string(buff[*cursor : *cursor+digitLen]) 168 169 *cursor += digitLen 170 171 i, err := strconv.Atoi(sub) 172 if err != nil { 173 return 0, e 174 } 175 176 if i >= min && i <= max { 177 return i, nil 178 } 179 180 return 0, e 181 } 182 183 func ParseHostname(buff []byte, cursor *int, l int) (string, error) { 184 from := *cursor 185 186 if from >= l { 187 return "", ErrHostnameTooShort 188 } 189 190 var to int 191 192 for to = from; to < l; to++ { 193 if buff[to] == ' ' { 194 break 195 } 196 } 197 198 hostname := buff[from:to] 199 200 *cursor = to 201 202 return string(hostname), nil 203 } 204 205 func ShowCursorPos(buff []byte, cursor int) { 206 fmt.Println(string(buff)) 207 padding := strings.Repeat("-", cursor) 208 fmt.Println(padding + "↑\n") 209 } 210 211 func (err *ParserError) Error() string { 212 return err.ErrorString 213 }