-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
dual_mode_logger.go
103 lines (84 loc) · 2.87 KB
/
dual_mode_logger.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
/*
Copyright The Velero Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package logging
import (
"compress/gzip"
"io"
"os"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// DualModeLogger is a thread safe logger interface to write logs to dual targets, one of which
// is a persist file, so that the log could be further transferred.
type DualModeLogger interface {
logrus.FieldLogger
// DoneForPersist stops outputting logs to the persist file
DoneForPersist(log logrus.FieldLogger)
// GetPersistFile moves the persist file pointer to beginning and returns it
GetPersistFile() (*os.File, error)
// Dispose closes the temp file pointer and removes the file
Dispose(log logrus.FieldLogger)
}
type tempFileLogger struct {
logrus.FieldLogger
logger *logrus.Logger
file *os.File
w *gzip.Writer
}
// NewTempFileLogger creates a DualModeLogger instance that writes logs to both Stdout and a file in the temp folder.
func NewTempFileLogger(logLevel logrus.Level, logFormat Format, hook *LogHook, fields logrus.Fields) (DualModeLogger, error) {
file, err := os.CreateTemp("", "")
if err != nil {
return nil, errors.Wrap(err, "error creating temp file")
}
w := gzip.NewWriter(file)
logger := DefaultLogger(logLevel, logFormat)
logger.Out = io.MultiWriter(os.Stdout, w)
if hook != nil {
logger.Hooks.Add(hook)
}
return &tempFileLogger{
FieldLogger: logger.WithFields(fields),
logger: logger,
file: file,
w: w,
}, nil
}
func (p *tempFileLogger) DoneForPersist(log logrus.FieldLogger) {
p.logger.SetOutput(os.Stdout)
if err := p.w.Close(); err != nil {
log.WithError(err).Warn("error closing gzip writer")
}
}
func (p *tempFileLogger) GetPersistFile() (*os.File, error) {
if _, err := p.file.Seek(0, 0); err != nil {
return nil, errors.Wrap(err, "error resetting log file offset to 0")
}
return p.file, nil
}
func (p *tempFileLogger) Dispose(log logrus.FieldLogger) {
p.w.Close()
closeAndRemoveFile(p.file, log)
}
func closeAndRemoveFile(file *os.File, log logrus.FieldLogger) {
if file == nil {
log.Debug("Skipping removal of temp log file due to nil file pointer")
return
}
if err := file.Close(); err != nil {
log.WithError(err).WithField("file", file.Name()).Warn("error closing temp log file")
}
if err := os.Remove(file.Name()); err != nil {
log.WithError(err).WithField("file", file.Name()).Warn("error removing temp log file")
}
}