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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
// Package log implements a basic level based logger
package log
import (
"fmt"
"io"
"log"
"os"
"path"
"github.com/eduvpn/eduvpn-common/internal/util"
"github.com/eduvpn/eduvpn-common/types"
)
// FileLogger defines the type of logger that this package implements
// As the name suggests, it saves the log to a file
type FileLogger struct {
// Level indicates which maximum level this logger actually forwards to the file
Level LogLevel
// file represents a pointer to the open log file
file *os.File
}
type LogLevel int8
const (
// LevelNotSet indicates level not set, not allowed
LevelNotSet LogLevel = iota
// LevelDebug indicates that the message is not an error but is there for debugging
LevelDebug
// LevelInfo indicates that the message is not an error but is there for additional information
LevelInfo
// LevelWarning indicates only a warning, the app still functions
LevelWarning
// LevelError indicates a generic error, the app still functions but some functionality might not work
LevelError
// LevelFatal indicates a fatal error, the app cannot function correctly when such an error occurs
LevelFatal
)
// String returns the string of each level
func (e LogLevel) String() string {
switch e {
case LevelNotSet:
return "NOTSET"
case LevelDebug:
return "DEBUG"
case LevelInfo:
return "INFO"
case LevelWarning:
return "WARNING"
case LevelError:
return "ERROR"
case LevelFatal:
return "FATAL"
default:
return "UNKNOWN"
}
}
// Init initializes the logger by forwarding a max level 'level' and a directory 'directory' where the log should be stored
// If the logger cannot be initialized, for example an error in opening the log file, an error is returned
func (logger *FileLogger) Init(level LogLevel, directory string) error {
errorMessage := "failed creating log"
configDirErr := util.EnsureDirectory(directory)
if configDirErr != nil {
return types.NewWrappedError(errorMessage, configDirErr)
}
logFile, logOpenErr := os.OpenFile(
logger.filename(directory),
os.O_RDWR|os.O_CREATE|os.O_APPEND,
0o666,
)
if logOpenErr != nil {
return types.NewWrappedError(errorMessage, logOpenErr)
}
multi := io.MultiWriter(os.Stdout, logFile)
log.SetOutput(multi)
logger.file = logFile
logger.Level = level
return nil
}
// Inherit logs an error with a label using the error level of the error
func (logger *FileLogger) Inherit(label string, err error) {
level := types.GetErrorLevel(err)
msg := fmt.Sprintf("%s with err: %s", label, types.GetErrorTraceback(err))
switch level {
case types.ErrInfo:
logger.Info(msg)
case types.ErrWarning:
logger.Warning(msg)
case types.ErrOther:
logger.Error(msg)
case types.ErrFatal:
logger.Fatal(msg)
}
}
// Debug logs a message with parameters as level LevelDebug
func (logger *FileLogger) Debug(msg string, params ...interface{}) {
logger.log(LevelDebug, msg, params...)
}
// Debug logs a message with parameters as level LevelInfo
func (logger *FileLogger) Info(msg string, params ...interface{}) {
logger.log(LevelInfo, msg, params...)
}
// Debug logs a message with parameters as level LevelWarning
func (logger *FileLogger) Warning(msg string, params ...interface{}) {
logger.log(LevelWarning, msg, params...)
}
// Debug logs a message with parameters as level LevelError
func (logger *FileLogger) Error(msg string, params ...interface{}) {
logger.log(LevelError, msg, params...)
}
// Debug logs a message with parameters as level LevelFatal
func (logger *FileLogger) Fatal(msg string, params ...interface{}) {
logger.log(LevelFatal, msg, params...)
}
// Close closes the logger by closing the internal file
func (logger *FileLogger) Close() {
logger.file.Close()
}
// filename returns the filename of the logger by returning the full path as a string
func (logger *FileLogger) filename(directory string) string {
return path.Join(directory, "log")
}
// log logs as level 'level' a message 'msg' with parameters 'params'
func (logger *FileLogger) log(level LogLevel, msg string, params ...interface{}) {
if level >= logger.Level && logger.Level != LevelNotSet {
formattedMsg := fmt.Sprintf(msg, params...)
format := fmt.Sprintf("- Go - %s - %s", level.String(), formattedMsg)
// To log file
log.Println(format)
}
}
|