-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
108 lines (88 loc) · 2.52 KB
/
main.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
package main
import (
"bufio"
"fmt"
"os"
"regexp"
"strings"
"text/template"
"github.com/go-logfmt/logfmt"
)
// main is the entrypoint for the program
func main() {
joinedArgs := ""
if len(os.Args) > 1 {
joinedArgs = strings.Join(os.Args[1:], " ")
}
filterPart, formatPart := splitArgs(joinedArgs)
filter := readFilter(filterPart)
format := readFormat(formatPart)
scan(filter, format)
}
// splitArgs splits command line arguments into a filter potion and a format
// portion; the filter is everything before the last '|' character, and the format
// is everything after it
func splitArgs(args string) (string, string) {
splitInd := strings.LastIndex(args, "|")
var likelyFormat = regexp.MustCompile(`[\.]`)
var likelyFilter = regexp.MustCompile(`[=!~]`)
if splitInd == -1 {
if likelyFormat.MatchString(args) && !likelyFilter.MatchString(args) {
// looks like a format string
return "", args
} else if likelyFilter.MatchString(args) && !likelyFormat.MatchString(args) {
// looks like a filter
filter := strings.Replace(args, "|", "", 0)
return filter, ""
} else if args != "" {
// just guess - it's a format probably
os.Stderr.WriteString("WARN: Ambiguous input; assuming format not filter\n")
return "", args
} else {
// no format or filter given
os.Stderr.WriteString("WARN: No filter or format given\n")
return "", ""
}
}
filter := args[:splitInd]
filter = strings.Replace(filter, "|", "", 0)
format := args[splitInd+1:]
format = strings.Trim(format, " ")
return filter, format
}
// scan is the main loop of the program, scanning os.Stdin until it ends and
// parsing/printing matching lines
func scan(filter []Filter, format *template.Template) {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
text := scanner.Text()
parsed := parseLine(text)
if len(parsed) > 0 {
if !matchesFilter(filter, parsed) {
continue
}
if format != nil {
formatLine(parsed, format)
} else {
// if no format was given, print the whole line
dump(parsed)
}
}
}
if err := scanner.Err(); err != nil {
fmt.Printf("Error scanning: %v", err)
}
}
// parseLine parses a single line of logfmt into a map of key/value pairs that
// can be processed for matches and output formatting
func parseLine(line string) map[string]string {
decoder := logfmt.NewDecoder(strings.NewReader(line))
decoder.ScanRecord()
data := map[string]string{}
for decoder.ScanKeyval() {
key := string(decoder.Key())
val := string(decoder.Value())
data[key] = val
}
return data
}