Skip to content

Commit e6f8cbe

Browse files
pooknullhors
andauthored
K8SPSMDB-1197: fix healthcheck log rotation (#1826)
* K8SPSMDB-1197: fix healthcheck log rotation https://perconadev.atlassian.net/browse/K8SPSMDB-1197 * remove submodule * add dependency as simple dir instead of submodule * fix dockerfile * Revert "fix dockerfile" This reverts commit 90755fe. * fix dockerfile --------- Co-authored-by: Viacheslav Sarzhan <slava.sarzhan@percona.com>
1 parent addbff8 commit e6f8cbe

File tree

18 files changed

+2093
-68
lines changed

18 files changed

+2093
-68
lines changed

build/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ FROM --platform=${BUILDPLATFORM} golang:1.23 AS go_builder
22
WORKDIR /go/src/github.com/percona/percona-server-mongodb-operator
33

44
COPY go.mod go.sum ./
5+
COPY cmd/mongodb-healthcheck/logger/lumberjack ./cmd/mongodb-healthcheck/logger/lumberjack
56
RUN go mod download
67

78
ARG GIT_COMMIT
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package logger
2+
3+
import (
4+
"io"
5+
"os"
6+
"path/filepath"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/go-logr/logr"
11+
uzap "go.uber.org/zap"
12+
"go.uber.org/zap/zapcore"
13+
"gopkg.in/natefinch/lumberjack.v2"
14+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
15+
16+
"github.com/percona/percona-server-mongodb-operator/pkg/psmdb"
17+
)
18+
19+
type Logger struct {
20+
logRotateWriter *lumberjack.Logger
21+
logr.Logger
22+
}
23+
24+
func New() *Logger {
25+
logPath := filepath.Join(psmdb.MongodDataVolClaimName, "logs", "mongodb-healthcheck.log")
26+
27+
return newLogger(logPath)
28+
}
29+
30+
func newLogger(logPath string) *Logger {
31+
logRotateWriter := &lumberjack.Logger{
32+
Filename: logPath,
33+
MaxSize: 100,
34+
MaxAge: 1,
35+
MaxBackups: 0,
36+
Compress: true,
37+
}
38+
39+
zapOpts := zap.Options{
40+
Encoder: getLogEncoder(),
41+
Level: getLogLevel(),
42+
DestWriter: io.MultiWriter(os.Stderr, logRotateWriter),
43+
}
44+
45+
return &Logger{
46+
logRotateWriter: logRotateWriter,
47+
Logger: zap.New(zap.UseFlagOptions(&zapOpts)),
48+
}
49+
}
50+
51+
func (l *Logger) Rotate() error {
52+
return l.logRotateWriter.Rotate()
53+
}
54+
55+
func (l *Logger) Close() error {
56+
return l.logRotateWriter.Close()
57+
}
58+
59+
func getLogEncoder() zapcore.Encoder {
60+
consoleEnc := zapcore.NewConsoleEncoder(uzap.NewDevelopmentEncoderConfig())
61+
62+
s, found := os.LookupEnv("LOG_STRUCTURED")
63+
if !found {
64+
return consoleEnc
65+
}
66+
67+
useJSON, err := strconv.ParseBool(s)
68+
if err != nil {
69+
return consoleEnc
70+
}
71+
if !useJSON {
72+
return consoleEnc
73+
}
74+
75+
return zapcore.NewJSONEncoder(uzap.NewProductionEncoderConfig())
76+
}
77+
78+
func getLogLevel() zapcore.LevelEnabler {
79+
defaultLogLevel := zapcore.DebugLevel
80+
81+
l, found := os.LookupEnv("LOG_LEVEL")
82+
if !found {
83+
return defaultLogLevel
84+
}
85+
86+
switch strings.ToUpper(l) {
87+
case "DEBUG":
88+
return zapcore.DebugLevel
89+
case "INFO":
90+
return zapcore.InfoLevel
91+
case "ERROR":
92+
return zapcore.ErrorLevel
93+
default:
94+
return defaultLogLevel
95+
}
96+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Nate Finch
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# lumberjack [![GoDoc](https://godoc.org/gopkg.in/natefinch/lumberjack.v2?status.png)](https://godoc.org/gopkg.in/natefinch/lumberjack.v2) [![Build Status](https://travis-ci.org/natefinch/lumberjack.svg?branch=v2.0)](https://travis-ci.org/natefinch/lumberjack) [![Build status](https://ci.appveyor.com/api/projects/status/00gchpxtg4gkrt5d)](https://ci.appveyor.com/project/natefinch/lumberjack) [![Coverage Status](https://coveralls.io/repos/natefinch/lumberjack/badge.svg?branch=v2.0)](https://coveralls.io/r/natefinch/lumberjack?branch=v2.0)
2+
3+
### Lumberjack is a Go package for writing logs to rolling files.
4+
5+
Package lumberjack provides a rolling logger.
6+
7+
Note that this is v2.0 of lumberjack, and should be imported using gopkg.in
8+
thusly:
9+
10+
import "gopkg.in/natefinch/lumberjack.v2"
11+
12+
The package name remains simply lumberjack, and the code resides at
13+
https://github.com/natefinch/lumberjack under the v2.0 branch.
14+
15+
Lumberjack is intended to be one part of a logging infrastructure.
16+
It is not an all-in-one solution, but instead is a pluggable
17+
component at the bottom of the logging stack that simply controls the files
18+
to which logs are written.
19+
20+
Lumberjack plays well with any logging package that can write to an
21+
io.Writer, including the standard library's log package.
22+
23+
Lumberjack assumes that only one process is writing to the output files.
24+
Using the same lumberjack configuration from multiple processes on the same
25+
machine will result in improper behavior.
26+
27+
28+
**Example**
29+
30+
To use lumberjack with the standard library's log package, just pass it into the SetOutput function when your application starts.
31+
32+
Code:
33+
34+
```go
35+
log.SetOutput(&lumberjack.Logger{
36+
Filename: "/var/log/myapp/foo.log",
37+
MaxSize: 500, // megabytes
38+
MaxBackups: 3,
39+
MaxAge: 28, //days
40+
Compress: true, // disabled by default
41+
})
42+
```
43+
44+
45+
46+
## type Logger
47+
``` go
48+
type Logger struct {
49+
// Filename is the file to write logs to. Backup log files will be retained
50+
// in the same directory. It uses <processname>-lumberjack.log in
51+
// os.TempDir() if empty.
52+
Filename string `json:"filename" yaml:"filename"`
53+
54+
// MaxSize is the maximum size in megabytes of the log file before it gets
55+
// rotated. It defaults to 100 megabytes.
56+
MaxSize int `json:"maxsize" yaml:"maxsize"`
57+
58+
// MaxAge is the maximum number of days to retain old log files based on the
59+
// timestamp encoded in their filename. Note that a day is defined as 24
60+
// hours and may not exactly correspond to calendar days due to daylight
61+
// savings, leap seconds, etc. The default is not to remove old log files
62+
// based on age.
63+
MaxAge int `json:"maxage" yaml:"maxage"`
64+
65+
// MaxBackups is the maximum number of old log files to retain. The default
66+
// is to retain all old log files (though MaxAge may still cause them to get
67+
// deleted.)
68+
MaxBackups int `json:"maxbackups" yaml:"maxbackups"`
69+
70+
// LocalTime determines if the time used for formatting the timestamps in
71+
// backup files is the computer's local time. The default is to use UTC
72+
// time.
73+
LocalTime bool `json:"localtime" yaml:"localtime"`
74+
75+
// Compress determines if the rotated log files should be compressed
76+
// using gzip. The default is not to perform compression.
77+
Compress bool `json:"compress" yaml:"compress"`
78+
// contains filtered or unexported fields
79+
}
80+
```
81+
Logger is an io.WriteCloser that writes to the specified filename.
82+
83+
Logger opens or creates the logfile on first Write. If the file exists and
84+
is less than MaxSize megabytes, lumberjack will open and append to that file.
85+
If the file exists and its size is >= MaxSize megabytes, the file is renamed
86+
by putting the current time in a timestamp in the name immediately before the
87+
file's extension (or the end of the filename if there's no extension). A new
88+
log file is then created using original filename.
89+
90+
Whenever a write would cause the current log file exceed MaxSize megabytes,
91+
the current file is closed, renamed, and a new log file created with the
92+
original name. Thus, the filename you give Logger is always the "current" log
93+
file.
94+
95+
Backups use the log file name given to Logger, in the form `name-timestamp.ext`
96+
where name is the filename without the extension, timestamp is the time at which
97+
the log was rotated formatted with the time.Time format of
98+
`2006-01-02T15-04-05.000` and the extension is the original extension. For
99+
example, if your Logger.Filename is `/var/log/foo/server.log`, a backup created
100+
at 6:30pm on Nov 11 2016 would use the filename
101+
`/var/log/foo/server-2016-11-04T18-30-00.000.log`
102+
103+
### Cleaning Up Old Log Files
104+
Whenever a new logfile gets created, old log files may be deleted. The most
105+
recent files according to the encoded timestamp will be retained, up to a
106+
number equal to MaxBackups (or all of them if MaxBackups is 0). Any files
107+
with an encoded timestamp older than MaxAge days are deleted, regardless of
108+
MaxBackups. Note that the time encoded in the timestamp is the rotation
109+
time, which may differ from the last time that file was written to.
110+
111+
If MaxBackups and MaxAge are both 0, no old log files will be deleted.
112+
113+
114+
115+
116+
117+
118+
119+
120+
121+
122+
123+
### func (\*Logger) Close
124+
``` go
125+
func (l *Logger) Close() error
126+
```
127+
Close implements io.Closer, and closes the current logfile.
128+
129+
130+
131+
### func (\*Logger) Rotate
132+
``` go
133+
func (l *Logger) Rotate() error
134+
```
135+
Rotate causes Logger to close the existing log file and immediately create a
136+
new one. This is a helper function for applications that want to initiate
137+
rotations outside of the normal rotation rules, such as in response to
138+
SIGHUP. After rotating, this initiates a cleanup of old log files according
139+
to the normal rules.
140+
141+
**Example**
142+
143+
Example of how to rotate in response to SIGHUP.
144+
145+
Code:
146+
147+
```go
148+
l := &lumberjack.Logger{}
149+
log.SetOutput(l)
150+
c := make(chan os.Signal, 1)
151+
signal.Notify(c, syscall.SIGHUP)
152+
153+
go func() {
154+
for {
155+
<-c
156+
l.Rotate()
157+
}
158+
}()
159+
```
160+
161+
### func (\*Logger) Write
162+
``` go
163+
func (l *Logger) Write(p []byte) (n int, err error)
164+
```
165+
Write implements io.Writer. If a write would cause the log file to be larger
166+
than MaxSize, the file is closed, renamed to include a timestamp of the
167+
current time, and a new log file is created using the original log file name.
168+
If the length of the write is greater than MaxSize, an error is returned.
169+
170+
171+
172+
173+
174+
175+
176+
177+
178+
- - -
179+
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// +build !linux
2+
3+
package lumberjack
4+
5+
import (
6+
"os"
7+
)
8+
9+
func chown(_ string, _ os.FileInfo) error {
10+
return nil
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package lumberjack
2+
3+
import (
4+
"os"
5+
"syscall"
6+
)
7+
8+
// osChown is a var so we can mock it out during tests.
9+
var osChown = os.Chown
10+
11+
func chown(name string, info os.FileInfo) error {
12+
f, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode())
13+
if err != nil {
14+
return err
15+
}
16+
f.Close()
17+
stat := info.Sys().(*syscall.Stat_t)
18+
return osChown(name, int(stat.Uid), int(stat.Gid))
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package lumberjack
2+
3+
import (
4+
"log"
5+
)
6+
7+
// To use lumberjack with the standard library's log package, just pass it into
8+
// the SetOutput function when your application starts.
9+
func Example() {
10+
log.SetOutput(&Logger{
11+
Filename: "/var/log/myapp/foo.log",
12+
MaxSize: 500, // megabytes
13+
MaxBackups: 3,
14+
MaxAge: 28, // days
15+
Compress: true, // disabled by default
16+
})
17+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module gopkg.in/natefinch/lumberjack.v2
2+
3+
go 1.13

cmd/mongodb-healthcheck/logger/lumberjack/go.sum

Whitespace-only changes.

0 commit comments

Comments
 (0)