Commit 03121daf9bc9e0dfb79abf36c1bf5f3f379353bf

Authored by Marko Tikvić
1 parent 7dab6e0054
Exists in master

extra padding on tracing message

Showing 1 changed file with 1 additions and 1 deletions   Show diff stats
1 package gologger 1 package gologger
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
5 "encoding/json" 5 "encoding/json"
6 "fmt" 6 "fmt"
7 "net/http" 7 "net/http"
8 "net/http/httputil" 8 "net/http/httputil"
9 "os" 9 "os"
10 "path/filepath" 10 "path/filepath"
11 "runtime" 11 "runtime"
12 "strings" 12 "strings"
13 "sync" 13 "sync"
14 "time" 14 "time"
15 ) 15 )
16 16
17 const dateTimeFormat = "2006-01-02 15:04:05" 17 const dateTimeFormat = "2006-01-02 15:04:05"
18 18
19 // Block ... 19 // Block ...
20 const ( 20 const (
21 MaxLogSize5MB int64 = 5 * 1024 * 1024 21 MaxLogSize5MB int64 = 5 * 1024 * 1024
22 MaxLogSize1MB int64 = 1 * 1024 * 1024 22 MaxLogSize1MB int64 = 1 * 1024 * 1024
23 MaxLogSize500KB int64 = 500 * 1024 23 MaxLogSize500KB int64 = 500 * 1024
24 MaxLogSize100KB int64 = 100 * 1024 24 MaxLogSize100KB int64 = 100 * 1024
25 MaxLogSize512B int64 = 512 25 MaxLogSize512B int64 = 512
26 ) 26 )
27 27
28 // Logger ... 28 // Logger ...
29 type Logger struct { 29 type Logger struct {
30 mu *sync.Mutex 30 mu *sync.Mutex
31 outputFile *os.File 31 outputFile *os.File
32 32
33 outputFileName string 33 outputFileName string
34 fullName string 34 fullName string
35 maxFileSize int64 35 maxFileSize int64
36 36
37 splitCount int 37 splitCount int
38 38
39 directory string 39 directory string
40 } 40 }
41 41
42 // New ... 42 // New ...
43 func New(name, dir string, maxFileSize int64) (logger *Logger, err error) { 43 func New(name, dir string, maxFileSize int64) (logger *Logger, err error) {
44 logger = &Logger{} 44 logger = &Logger{}
45 45
46 logger.outputFileName = name 46 logger.outputFileName = name
47 logger.mu = &sync.Mutex{} 47 logger.mu = &sync.Mutex{}
48 logger.maxFileSize = maxFileSize 48 logger.maxFileSize = maxFileSize
49 logger.directory = dir 49 logger.directory = dir
50 50
51 err = os.Mkdir(dir, os.ModePerm) 51 err = os.Mkdir(dir, os.ModePerm)
52 if err != nil { 52 if err != nil {
53 if !os.IsExist(err) { 53 if !os.IsExist(err) {
54 return nil, err 54 return nil, err
55 } 55 }
56 } 56 }
57 57
58 date := strings.Replace(time.Now().Format(dateTimeFormat), ":", ".", -1) 58 date := strings.Replace(time.Now().Format(dateTimeFormat), ":", ".", -1)
59 logger.outputFileName += " " + date 59 logger.outputFileName += " " + date
60 logger.fullName = logger.outputFileName + ".txt" 60 logger.fullName = logger.outputFileName + ".txt"
61 path := filepath.Join(dir, logger.fullName) 61 path := filepath.Join(dir, logger.fullName)
62 if logger.outputFile, err = os.Create(path); err != nil { 62 if logger.outputFile, err = os.Create(path); err != nil {
63 return nil, err 63 return nil, err
64 } 64 }
65 65
66 return logger, nil 66 return logger, nil
67 } 67 }
68 68
69 // Log ... 69 // Log ...
70 func (l *Logger) Log(format string, v ...interface{}) { 70 func (l *Logger) Log(format string, v ...interface{}) {
71 if l.outputFile == nil { 71 if l.outputFile == nil {
72 return 72 return
73 } 73 }
74 74
75 l.mu.Lock() 75 l.mu.Lock()
76 defer l.mu.Unlock() 76 defer l.mu.Unlock()
77 77
78 msg := fmt.Sprintf(format, v...) 78 msg := fmt.Sprintf(format, v...)
79 s := time.Now().Format(dateTimeFormat) + ": " + msg + "\n" 79 s := time.Now().Format(dateTimeFormat) + ": " + msg + "\n"
80 if l.shouldSplit(len(s)) { 80 if l.shouldSplit(len(s)) {
81 l.split() 81 l.split()
82 } 82 }
83 l.outputFile.WriteString(s) 83 l.outputFile.WriteString(s)
84 } 84 }
85 85
86 // Print ... 86 // Print ...
87 func (l *Logger) Print(format string, v ...interface{}) { 87 func (l *Logger) Print(format string, v ...interface{}) {
88 msg := fmt.Sprintf(format, v...) 88 msg := fmt.Sprintf(format, v...)
89 fmt.Printf("%s: %s\n", time.Now().Format(dateTimeFormat), msg) 89 fmt.Printf("%s: %s\n", time.Now().Format(dateTimeFormat), msg)
90 } 90 }
91 91
92 const MaxStackDepth = 10000 92 const MaxStackDepth = 10000
93 93
94 // CallStack 94 // CallStack
95 func CallStack() (stack string) { 95 func CallStack() (stack string) {
96 callers := make([]uintptr, MaxStackDepth) // min 1 96 callers := make([]uintptr, MaxStackDepth) // min 1
97 stackDepth := runtime.Callers(2, callers) 97 stackDepth := runtime.Callers(2, callers)
98 frames := runtime.CallersFrames(callers) 98 frames := runtime.CallersFrames(callers)
99 99
100 for i := 0; i < stackDepth; i++ { 100 for i := 0; i < stackDepth; i++ {
101 if i >= 2 { // skip runtime and startup 101 if i >= 2 { // skip runtime and startup
102 frame, next := frames.Next() 102 frame, next := frames.Next()
103 stack += fmt.Sprintf("[%s %d]\n", frame.File, frame.Line) 103 stack += fmt.Sprintf("[%s %d]\n", frame.File, frame.Line)
104 if !next { 104 if !next {
105 break 105 break
106 } 106 }
107 } 107 }
108 } 108 }
109 109
110 return 110 return
111 } 111 }
112 112
113 // PrintTrace ... 113 // PrintTrace ...
114 func (l *Logger) PrintTrace(format string, v ...interface{}) { 114 func (l *Logger) PrintTrace(format string, v ...interface{}) {
115 stack := CallStack() 115 stack := CallStack()
116 msg := fmt.Sprintf(format, v...) 116 msg := fmt.Sprintf(format, v...)
117 fmt.Printf("%s:\n%s\n%s\n", time.Now().Format(dateTimeFormat), stack, msg) 117 fmt.Printf("%s:\n%s\n%s\n", time.Now().Format(dateTimeFormat), stack, msg)
118 } 118 }
119 119
120 // Trace ... 120 // Trace ...
121 func (l *Logger) Trace(format string, v ...interface{}) { 121 func (l *Logger) Trace(format string, v ...interface{}) {
122 if l.outputFile == nil { 122 if l.outputFile == nil {
123 return 123 return
124 } 124 }
125 125
126 l.mu.Lock() 126 l.mu.Lock()
127 defer l.mu.Unlock() 127 defer l.mu.Unlock()
128 128
129 stack := CallStack() 129 stack := CallStack()
130 130
131 msg := fmt.Sprintf(format, v...) 131 msg := fmt.Sprintf(format, v...)
132 s := fmt.Sprintf("%s:\n%s\n%s\n", time.Now().Format(dateTimeFormat), stack, msg) 132 s := fmt.Sprintf("%s:\n%s\n%s\n\n", time.Now().Format(dateTimeFormat), stack, msg)
133 133
134 if l.shouldSplit(len(s)) { 134 if l.shouldSplit(len(s)) {
135 l.split() 135 l.split()
136 } 136 }
137 l.outputFile.WriteString(s) 137 l.outputFile.WriteString(s)
138 } 138 }
139 139
140 // PrintAndTrace ... 140 // PrintAndTrace ...
141 func (l *Logger) PrintAndTrace(format string, v ...interface{}) { 141 func (l *Logger) PrintAndTrace(format string, v ...interface{}) {
142 l.Print(format, v...) 142 l.Print(format, v...)
143 l.Trace(format, v...) 143 l.Trace(format, v...)
144 } 144 }
145 145
146 // LogHTTPRequest ... 146 // LogHTTPRequest ...
147 func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string { 147 func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string {
148 if userID == "" { 148 if userID == "" {
149 userID = "-" 149 userID = "-"
150 } 150 }
151 151
152 var b strings.Builder 152 var b strings.Builder
153 153
154 b.WriteString("Request:\n") 154 b.WriteString("Request:\n")
155 // CLF-like header 155 // CLF-like header
156 fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat)) 156 fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat))
157 157
158 body, err := httputil.DumpRequest(req, true) 158 body, err := httputil.DumpRequest(req, true)
159 if err != nil { 159 if err != nil {
160 fmt.Fprintf(os.Stderr, "%v\n", err) 160 fmt.Fprintf(os.Stderr, "%v\n", err)
161 } 161 }
162 162
163 const sepStr = "\r\n\r\n" 163 const sepStr = "\r\n\r\n"
164 sepIndex := bytes.Index(body, []byte(sepStr)) 164 sepIndex := bytes.Index(body, []byte(sepStr))
165 if sepIndex == -1 { 165 if sepIndex == -1 {
166 b.WriteString(string(body) + "\n\n") 166 b.WriteString(string(body) + "\n\n")
167 } else { 167 } else {
168 sepIndex += len(sepStr) 168 sepIndex += len(sepStr)
169 payload, _ := printJSON(body[sepIndex:]) 169 payload, _ := printJSON(body[sepIndex:])
170 b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n") 170 b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n")
171 } 171 }
172 172
173 return b.String() 173 return b.String()
174 } 174 }
175 175
176 const splitLine = "==============================================================" 176 const splitLine = "=============================================================="
177 177
178 // LogHTTPResponse ... 178 // LogHTTPResponse ...
179 func (l *Logger) LogHTTPResponse(status int, duration time.Duration, size int) string { 179 func (l *Logger) LogHTTPResponse(status int, duration time.Duration, size int) string {
180 return fmt.Sprintf("Response:\n%d %v %dB\n%s\n", status, duration, size, splitLine) 180 return fmt.Sprintf("Response:\n%d %v %dB\n%s\n", status, duration, size, splitLine)
181 } 181 }
182 182
183 // CombineHTTPLogs ... 183 // CombineHTTPLogs ...
184 func (l *Logger) CombineHTTPLogs(in string, out string) { 184 func (l *Logger) CombineHTTPLogs(in string, out string) {
185 if l.outputFile == nil { 185 if l.outputFile == nil {
186 return 186 return
187 } 187 }
188 188
189 l.mu.Lock() 189 l.mu.Lock()
190 defer l.mu.Unlock() 190 defer l.mu.Unlock()
191 191
192 msg := in + out 192 msg := in + out
193 if l.shouldSplit(len(msg)) { 193 if l.shouldSplit(len(msg)) {
194 l.split() 194 l.split()
195 } 195 }
196 l.outputFile.WriteString(msg) 196 l.outputFile.WriteString(msg)
197 } 197 }
198 198
199 // Close ... 199 // Close ...
200 func (l *Logger) Close() error { 200 func (l *Logger) Close() error {
201 if l.outputFile == nil { 201 if l.outputFile == nil {
202 return nil 202 return nil
203 } 203 }
204 204
205 return l.outputFile.Close() 205 return l.outputFile.Close()
206 } 206 }
207 207
208 func (l *Logger) split() error { 208 func (l *Logger) split() error {
209 if l.outputFile == nil { 209 if l.outputFile == nil {
210 return nil 210 return nil
211 } 211 }
212 212
213 // close old file 213 // close old file
214 err := l.outputFile.Close() 214 err := l.outputFile.Close()
215 if err != nil { 215 if err != nil {
216 return err 216 return err
217 } 217 }
218 218
219 // open new file 219 // open new file
220 l.splitCount++ 220 l.splitCount++
221 path := filepath.Join(l.directory, l.outputFileName+fmt.Sprintf("(%d)", l.splitCount)+".txt") 221 path := filepath.Join(l.directory, l.outputFileName+fmt.Sprintf("(%d)", l.splitCount)+".txt")
222 l.outputFile, err = os.Create(path) 222 l.outputFile, err = os.Create(path)
223 223
224 return err 224 return err
225 } 225 }
226 226
227 func (l *Logger) shouldSplit(nextEntrySize int) bool { 227 func (l *Logger) shouldSplit(nextEntrySize int) bool {
228 stats, _ := l.outputFile.Stat() 228 stats, _ := l.outputFile.Stat()
229 return int64(nextEntrySize) >= (l.maxFileSize - stats.Size()) 229 return int64(nextEntrySize) >= (l.maxFileSize - stats.Size())
230 } 230 }
231 231
232 func printJSON(in []byte) (out []byte, err error) { 232 func printJSON(in []byte) (out []byte, err error) {
233 var buf bytes.Buffer 233 var buf bytes.Buffer
234 err = json.Indent(&buf, in, "", " ") 234 err = json.Indent(&buf, in, "", " ")
235 return buf.Bytes(), err 235 return buf.Bytes(), err
236 } 236 }
237 237