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
110
111
112
113
114
115
116
117
118
119
120
121
|
package logformat
import (
"errors"
"fmt"
"strings"
"sync"
"time"
"github.com/mimecast/dtail/internal/config"
"github.com/mimecast/dtail/internal/mapr"
)
// ErrIgnoreFields indicates that the fields should be ignored.
var ErrIgnoreFields error = errors.New("Ignore this field set")
// Parser is used to parse the mapreduce information from the server log files.
type Parser interface {
// MakeFields creates a field map from an input log line.
MakeFields(string) (map[string]string, error)
}
type queryAwareParser interface {
setQuery(*mapr.Query)
}
// ParserFactory builds a Parser for a specific log format.
type ParserFactory func(hostname, timeZoneName string, timeZoneOffset int) (Parser, error)
var parserFactories = make(map[string]ParserFactory)
var parserFactoriesMu sync.RWMutex
func init() {
registerBuiltInParsers()
}
// RegisterParser registers or replaces a parser factory for a log format name.
func RegisterParser(logFormatName string, factory ParserFactory) error {
name := strings.TrimSpace(logFormatName)
if name == "" {
return errors.New("log format name cannot be empty")
}
if factory == nil {
return errors.New("parser factory cannot be nil")
}
parserFactoriesMu.Lock()
defer parserFactoriesMu.Unlock()
parserFactories[name] = factory
return nil
}
func getParserFactory(logFormatName string) (ParserFactory, bool) {
parserFactoriesMu.RLock()
defer parserFactoriesMu.RUnlock()
factory, found := parserFactories[logFormatName]
return factory, found
}
func registerBuiltInParsers() {
mustRegisterParser("generic", wrapParserFactory(newGenericParser))
mustRegisterParser("generickv", wrapParserFactory(newGenericKVParser))
mustRegisterParser("csv", wrapParserFactory(newCSVParser))
mustRegisterParser("mimecast", wrapParserFactory(newMimecastParser))
mustRegisterParser("mimecastgeneric", wrapParserFactory(newMimecastGenericParser))
mustRegisterParser("default", wrapParserFactory(newDefaultParser))
mustRegisterParser("custom1", wrapParserFactory(newCustom1Parser))
mustRegisterParser("custom2", wrapParserFactory(newCustom2Parser))
}
func mustRegisterParser(logFormatName string, factory ParserFactory) {
if err := RegisterParser(logFormatName, factory); err != nil {
panic(err)
}
}
func wrapParserFactory[T Parser](factory func(string, string, int) (T, error)) ParserFactory {
return func(hostname, timeZoneName string, timeZoneOffset int) (Parser, error) {
return factory(hostname, timeZoneName, timeZoneOffset)
}
}
// NewParser returns a new log parser.
func NewParser(logFormatName string, query *mapr.Query) (Parser, error) {
hostname, err := config.Hostname()
if err != nil {
return nil, err
}
now := time.Now()
timeZoneName, timeZoneOffset := now.Zone()
if parserFactory, found := getParserFactory(logFormatName); found {
parser, err := parserFactory(hostname, timeZoneName, timeZoneOffset)
configureParserQuery(parser, query)
return parser, err
}
defaultFactory, found := getParserFactory("default")
if !found {
return nil, fmt.Errorf("No '%s' mapr log format and no default parser registered", logFormatName)
}
p, err := defaultFactory(hostname, timeZoneName, timeZoneOffset)
if err != nil {
return p, fmt.Errorf("No '%s' mapr log format and problem creating default one: %v",
logFormatName, err)
}
configureParserQuery(p, query)
return p, fmt.Errorf("No '%s' mapr log format", logFormatName)
}
func configureParserQuery(parser Parser, query *mapr.Query) {
if parser == nil {
return
}
queryAware, ok := parser.(queryAwareParser)
if !ok {
return
}
queryAware.setQuery(query)
}
|