summaryrefslogtreecommitdiff
path: root/internal/mapr/logformat/parser.go
blob: c53729a24c227dc16d4f6f0db607e0ad854d11c0 (plain)
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
package logformat

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"
	"time"

	"github.com/mimecast/dtail/internal/io/logger"
	"github.com/mimecast/dtail/internal/mapr"
)

// Parser is used to parse the mapreduce information from the server log files.
type Parser struct {
	hostname           string
	logFormatName      string
	makeFieldsFunc     reflect.Value
	makeFieldsReceiver reflect.Value
	timeZoneName       string
	timeZoneOffset     string
}

// NewParser returns a new log parser.
func NewParser(logFormatName string, query *mapr.Query) (*Parser, error) {
	hostname, err := os.Hostname()

	if err != nil {
		return nil, err
	}

	now := time.Now()
	zone, offset := now.Zone()

	p := Parser{
		hostname:       hostname,
		timeZoneName:   zone,
		timeZoneOffset: fmt.Sprintf("%d", offset),
	}

	err = p.reflectLogFormat(logFormatName)
	if err != nil {
		return nil, err
	}

	return &p, nil
}

// The aim of this is that everyone can plug in their own mapr log format
// parsing method to DTail. Just add a method MakeFieldsMODULENAME to type
// Parser. Whereas MODULENAME must be a upeprcase string.
func (p *Parser) reflectLogFormat(logFormatName string) error {
	methodName := fmt.Sprintf("MakeFields%s", strings.ToUpper(logFormatName))

	rt := reflect.TypeOf(p)
	method, ok := rt.MethodByName(methodName)
	if !ok {
		return errors.New("No such mapr log format module: " + methodName)
	}

	p.makeFieldsFunc = method.Func
	p.makeFieldsReceiver = reflect.ValueOf(p)

	return nil
}

// MakeFields is for returning the fields from a given log line.
func (p *Parser) MakeFields(maprLine string) (fields map[string]string, err error) {
	inputValues := []reflect.Value{p.makeFieldsReceiver, reflect.ValueOf(maprLine)}
	returnValues := p.makeFieldsFunc.Call(inputValues)

	errInterface := returnValues[1].Interface()

	if errInterface == nil {
		fields, err = returnValues[0].Interface().(map[string]string), nil
		logger.Trace("parser.MakeFields", fields, err)
		return
	}

	fields, err = returnValues[0].Interface().(map[string]string), errInterface.(error)
	logger.Trace("parser.MakeFields", fields, err)

	return
}