-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathglogrotate.go
123 lines (107 loc) · 2.82 KB
/
glogrotate.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
/*
Gzips and deletes log files generated by glog http://github.com/golang/glog
Basic usage:
glogrotate -base=/var/log -maxage=240h myapp myotherapp
glogrotate will not touch the current log files. There are different timeouts for the INFO, WARNING, and ERROR log levels.
*/
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
const (
defaultDeleteInfoAfter = 30 * 24 * time.Hour
defaultWarnMult = 2
defaultErrorMult = 3
)
var (
base = flag.String("base", "/var/log/", "log subdir")
deleteInfoAfter = flag.Duration("maxage", defaultDeleteInfoAfter, "delete INFO files older than this")
warnMult = flag.Int("warn", defaultWarnMult, "multiplier relative to maxage for WARNING files")
errorMult = flag.Int("error", defaultErrorMult, "multiplier relative to maxage for ERROR/FATAL files")
verbose = flag.Bool("v", false, "verbose")
)
func main() {
flag.Parse()
for _, log := range flag.Args() {
clean(*base+"/"+log, log)
}
}
func clean(dir, name string) {
if *verbose {
fmt.Printf("clean %s/%s*...\n", dir, name)
}
fs, err := filepath.Glob(dir + "/" + name + "*")
if err != nil {
fatalf("file error: %s", err)
}
doNotTouch := map[string]struct{}{}
var candidates []string
for _, f := range fs {
if t, err := os.Readlink(f); err == nil {
// it's a symlink to the current file.
a := filepath.Join(filepath.Dir(f), t)
doNotTouch[a] = struct{}{}
continue
}
candidates = append(candidates, f)
}
for _, f := range candidates {
if _, ok := doNotTouch[f]; ok {
if *verbose {
fmt.Printf("don't touch: %s\n", f)
}
continue
}
// we want the date from 'one.rz-reqmngt1-eu.root.log.ERROR.20150320-103857.29198'
// (might have a .gz suffix)
fields := strings.Split(f, ".")
if len(fields) < 3 {
fatalf("unexpected filename: %q", f)
}
if fields[len(fields)-1] == `gz` {
fields = fields[:len(fields)-1]
}
var dAfter time.Duration
level := fields[len(fields)-3]
switch level {
case "INFO":
dAfter = *deleteInfoAfter
case "WARNING":
dAfter = time.Duration(*warnMult) * (*deleteInfoAfter)
case "ERROR", "FATAL":
dAfter = time.Duration(*errorMult) * (*deleteInfoAfter)
default:
fatalf("weird log level: %q", level)
}
d, err := time.Parse("20060102", strings.SplitN(fields[len(fields)-2], "-", 2)[0])
if err != nil {
fatalf("invalid date: %s", err)
}
if d.Before(time.Now().Add(-dAfter)) {
if *verbose {
fmt.Printf("delete %s\n", f)
}
os.Remove(f)
continue
}
if !strings.HasSuffix(f, ".gz") {
if *verbose {
fmt.Printf("gzipping %s...\n", f)
}
if err := exec.Command("gzip", f).Run(); err != nil {
fatalf("gzip: %s", err)
}
}
}
}
func fatalf(f string, args ...interface{}) {
fmt.Fprintf(os.Stderr, f, args)
fmt.Fprint(os.Stderr, "\n")
os.Exit(1)
}