summaryrefslogtreecommitdiffstats
path: root/cmd/grv/log.go
blob: b21c5ac09da663e63b2728b4791cf27be6ca07e4 (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
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
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"

	log "github.com/Sirupsen/logrus"
)

const (
	logLogrusRepo     = "github.com/Sirupsen/logrus"
	logFileDateFormat = "2006-01-02 15:04:05.000-0700"
)

var logFile string

type fileHook struct{}

func (hook fileHook) Fire(entry *log.Entry) (err error) {
	pc := make([]uintptr, 5)
	cnt := runtime.Callers(6, pc)

	for i := 0; i < cnt; i++ {
		fu := runtime.FuncForPC(pc[i] - 1)
		name := fu.Name()

		if !strings.Contains(name, logLogrusRepo) {
			file, line := fu.FileLine(pc[i] - 1)
			entry.Data["file"] = fmt.Sprintf("%v:%v", path.Base(file), line)
			break
		}
	}

	return
}

func (hook fileHook) Levels() []log.Level {
	return log.AllLevels
}

type logFormatter struct{}

func (formatter logFormatter) Format(entry *log.Entry) ([]byte, error) {
	var buffer bytes.Buffer
	file, _ := entry.Data["file"].(string)

	formatter.formatBracketEntry(&buffer, entry.Time.Format(logFileDateFormat))
	formatter.formatBracketEntry(&buffer, strings.ToUpper(entry.Level.String()))
	formatter.formatBracketEntry(&buffer, file)

	buffer.WriteString("- ")

	for _, char := range entry.Message {
		switch {
		case char == '\n':
			buffer.WriteString("\\n")
		case char < 32 || char == 127:
			buffer.WriteString(NonPrintableCharString(char))
		default:
			buffer.WriteRune(char)
		}
	}

	buffer.WriteRune('\n')

	return buffer.Bytes(), nil
}

func (formatter logFormatter) formatBracketEntry(buffer *bytes.Buffer, value string) {
	buffer.WriteRune('[')
	buffer.WriteString(value)
	buffer.WriteString("] ")
}

// LogFile returns the path of the file GRV is logging to
func LogFile() string {
	return logFile
}

// InitialiseLogging sets up logging
func InitialiseLogging(logLevel, logFilePath string) {
	if logLevel == MnLogLevelDefault {
		log.SetOutput(ioutil.Discard)
		return
	}

	logFile = logFilePath

	logLevels := map[string]log.Level{
		"PANIC": log.PanicLevel,
		"FATAL": log.FatalLevel,
		"ERROR": log.ErrorLevel,
		"WARN":  log.WarnLevel,
		"INFO":  log.InfoLevel,
		"DEBUG": log.DebugLevel,
	}

	if level, ok := logLevels[logLevel]; ok {
		log.SetLevel(level)
	} else {
		log.Fatalf("Invalid logLevel: %v", logLevel)
	}

	file, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		log.Fatalf("Unable to open log file %v for writing: %v", logFilePath, err)
	}

	log.SetOutput(file)

	log.SetFormatter(logFormatter{})

	log.AddHook(fileHook{})
}