-
Notifications
You must be signed in to change notification settings - Fork 0
/
ownCloudLogAnalyser.go
134 lines (119 loc) · 4.2 KB
/
ownCloudLogAnalyser.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"os"
"fmt"
"flag"
"log"
"strings"
"encoding/json"
"strconv"
"gopkg.in/Knetic/govaluate.v3"
"github.com/hpcloud/tail"
)
type logLine struct {
lineNumber int
raw string
decodedData map[string]interface{}
showLine bool
}
// decodes the raw data and updates logLine.decodedData
func (logLine *logLine) jsonDecode() {
//parse unstructured json
//see https://www.sohamkamani.com/blog/2017/10/18/parsing-json-in-golang/
err := json.Unmarshal([]byte(logLine.raw), &logLine.decodedData)
checkErr("JSON error in line: " + strconv.Itoa(logLine.lineNumber) + ".", err)
}
// evaluates the given filter and updates logLine.showLine according to the filter
func (logLine *logLine) evaluateFilter(filter string) {
filterExpression, err := govaluate.NewEvaluableExpression(filter);
checkErr("Cannot evaluate filter string.", err)
filterResult, err := filterExpression.Evaluate(logLine.decodedData);
if filterResult!=true || err != nil{
logLine.showLine = false
}
}
// prints the formated output
func (logLine *logLine) printLine(showLineCounter bool, listOfKeysToView []string) {
if logLine.showLine {
if showLineCounter {
fmt.Printf("%v: ", logLine.lineNumber)
}
if len(listOfKeysToView) > 0 {
//show only the keys we requested
for _, jsonKey := range listOfKeysToView {
fmt.Printf("%v: %v\t", jsonKey, logLine.decodedData[jsonKey])
}
fmt.Println()
} else {
fmt.Println(logLine.raw)
}
}
}
func checkErr(message string, err error) {
//for error handling see https://davidnix.io/post/error-handling-in-go/
if err != nil {
log.Fatal("ERROR! ", message, " Details: ", err)
}
}
func main() {
fileNamePtr := flag.String("file", "", "the ownCloud log file")
followPtr := flag.Bool("f", false, "output appended data as the file grows")
showLineCounterPtr := flag.Bool("linenumbers", false, "show the line numbers")
listOfKeysToViewStringPtr := flag.String("view", "", "list of keys to be shown (separate by comma), if empty all are shown")
filterPtr := flag.String("filter", "", "filter the output by logical expressions e.g. \"user=='admin'&&level>=3\"")
tailPtr := flag.Int64("tail", 0, "show only the n last lines")
flag.Parse()
lineCounter := 1
needJsonDecode := false
//split the list of keys to view into slices
listOfKeysToView := make([]string,0)
if *listOfKeysToViewStringPtr != "" || *filterPtr != "" {
needJsonDecode = true
}
if *listOfKeysToViewStringPtr != "" {
listOfKeysToView = strings.Split(*listOfKeysToViewStringPtr, ",")
}
var seekOffset int64 = 0
if *tailPtr > 0 {
var lineBreaksCounter int64
logFile, err := os.Open(*fileNamePtr)
defer logFile.Close()
checkErr("Failed to read the logfile.", err)
for lineBreaksCounter = 0; lineBreaksCounter <= *tailPtr; {
seekOffset--
_, err = logFile.Seek(seekOffset, os.SEEK_END)
checkErr("Failed to read the logfile.", err)
readByte := make([]byte, 1)
_, err = logFile.Read(readByte)
checkErr("Failed to read the logfile.", err)
if string(readByte) == "\n" {
lineBreaksCounter++
}
}
}
//main loop to loop through the log file
logFile, err := tail.TailFile(
*fileNamePtr,
tail.Config{
Follow: *followPtr,
MustExist: true})
if *tailPtr > 0 {
logFile.Location = &tail.SeekInfo{seekOffset+1, os.SEEK_END}
}
checkErr("Failed to read the logfile.", err)
for line := range logFile.Lines {
currentLogLine := logLine {
raw: line.Text,
lineNumber: lineCounter,
showLine: true }
if needJsonDecode {
currentLogLine.jsonDecode()
}
if *filterPtr != "" {
currentLogLine.evaluateFilter(*filterPtr)
}
currentLogLine.printLine(*showLineCounterPtr, listOfKeysToView)
lineCounter++
}
checkErr("Failed to read the logfile.", logFile.Err())
}