-
Notifications
You must be signed in to change notification settings - Fork 0
/
extractors.go
109 lines (91 loc) · 2.3 KB
/
extractors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package hunkee
import (
"errors"
"log"
"reflect"
"strings"
)
const (
unexportedTag = "-"
libtag = "hunk"
)
var debug bool
// parseLine processing one log line into structure
func (p *Parser) parseLine(line string, dest interface{}) (err error) {
if line == "" || line == "\n" {
return ErrEmptyLine
}
var (
offset int
lineLen = len(line)
w = p.mapper.aquireWorker()
)
defer w.free()
if debug {
log.Printf("Entry: %q Len: %d\n", line, len(line))
}
// Check if line has commentary prefix. If so, skip
if p.mapper.prefixActive && strings.HasPrefix(line, p.mapper.comPrefix) {
if debug {
log.Printf("Entry: %q skipped due to matched prefix %q", line, p.mapper.comPrefix)
}
return
}
destination := reflect.Indirect(reflect.ValueOf(dest))
for field := w.first(); field != nil; field = w.next() {
var token string
start := offset
// if token separator is 0, no need to search first occurrence
if p.mapper.tokenSep != 0 {
start = findNextSep(line, offset, p.mapper.tokenSep)
if start < 0 {
return errors.New("provided line has less tokens than expected")
}
}
end := findNextSep(line, start, p.mapper.tokenSep)
// findNextSpace returns -1 if no other space found
// so if no space found - read line from current position
// to the end of line, else read all between offset and end
if end < offset || end >= lineLen-1 {
token = line[offset:]
} else {
token = line[offset:end]
}
if field.ftype == typeIgnored {
offset = end
continue
}
token = strings.Trim(strings.TrimSpace(token), string(p.mapper.tokenSep))
if debug {
log.Printf("Field: %q Token: %q Pos:[%d:%d] HasRaw: %t TimeOption: %#+v\n",
field.name, token, offset, end, field.hasRaw, field.timeOptions)
}
if err = p.mapper.processField(field, destination, token); err != nil {
return err
}
offset = end
}
return
}
// if provided sep is empty, space lookup will be used instead
func findNextSep(line string, start int, sep byte) int {
if start >= len(line) {
return -1
}
if sep == 0 {
sep = ' '
}
for i := start + 1; i < len(line); i++ {
if line[i] == sep || line[i] == '\n' {
return i
}
}
return -1
}
// deref is Indirect for reflect.Types
func deref(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}