-
Notifications
You must be signed in to change notification settings - Fork 0
/
logman.go
145 lines (123 loc) · 2.9 KB
/
logman.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package logman
import (
"os"
"time"
"strings"
"strconv"
"fmt"
"errors"
)
type LogMan struct {
path string
duration time.Duration;
size int64;
lastFileStart time.Time;
layout string;
}
func isLetter(c byte) bool {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
}
const (
B = "B"
KiB = "KiB"
MiB = "MiB"
GiB = "GiB"
)
func parseFileSize(size string) (sz int64, err error) {
var (
num int64
mult int64
unit string
)
for i := len(size)-1; i >= 0 && isLetter(size[i]); i-- {
unit = string(size[i]) + unit
}
switch unit {
case B:
mult = 1<<(10*0)
case KiB:
mult = 1<<(10*1)
case MiB:
mult = 1<<(10*2)
case GiB:
mult = 1<<(10*3)
default:
err = errors.New("logman: unknown file size units " + "'" + unit + "'")
return
}
num, err = strconv.ParseInt(size[:len(size) - len(unit)], 10, 64)
if err != nil {
err = errors.New("logman: could not parse file size " + "'" + string(num) + "'")
return
}
sz = mult * num
return
}
func New(path string, duration string, size string) *LogMan {
dur, err := time.ParseDuration(duration)
if err != nil {
fmt.Errorf("[ERROR] Could not parse duration: %s\n", err)
os.Exit(1)
}
if dur < time.Second {
fmt.Println("[ERROR] Duration must be greater than, or equal to, 1 second")
os.Exit(1)
}
if !strings.HasSuffix(path, "/") {
path += "/"
}
sz, err := parseFileSize(size)
if err != nil {
fmt.Printf("[ERROR] Could not parse file size: %s\n", err)
os.Exit(1)
}
return &LogMan{
path: path,
duration: dur,
size: sz,
layout: time.RFC3339Nano,
}
}
func (lm *LogMan) getLogFileName(logSize int64) (name string, err error) {
// first write
if lm.lastFileStart.IsZero() {
lm.lastFileStart = time.Now()
name = lm.lastFileStart.Format(lm.layout) + ".log"
return
}
// duration interval passed
if slots := time.Since(lm.lastFileStart) / lm.duration; slots >= 1 {
newTime := lm.lastFileStart.Add(slots * lm.duration)
lm.lastFileStart = newTime
name = newTime.Format(lm.layout) + ".log"
return
}
// file size limit reached
lastFileName := lm.path + lm.lastFileStart.Format(lm.layout) + ".log"
fInfo, err := os.Lstat(lastFileName)
if err != nil {
err = errors.New("logman: could not lstat " + lastFileName)
return
}
if size := fInfo.Size() + logSize; size >= lm.size {
newTime := time.Now()
lm.lastFileStart = newTime
name = newTime.Format(lm.layout) + ".log"
return
}
name = lm.lastFileStart.Format(lm.layout) + ".log"
return
}
func (lm *LogMan) Write(p []byte) (n int, err error) {
fileName, err := lm.getLogFileName(int64(len(p)))
if err != nil {
err = errors.New(fmt.Sprintf("logman: could not retrieve log file name: %s", err))
return
}
f, err := os.OpenFile(lm.path + fileName, os.O_WRONLY | os.O_APPEND | os.O_CREATE, 0666)
if err != nil {
err = errors.New(fmt.Sprintf("logman: could not open log file: %s", err))
return
}
return f.Write(p)
}