Commit a7081e581392838008eb009222c7692981ff4634

Authored by Marko Tikvić
1 parent b45f88e17f
Exists in master

pretty print json

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