Commit a7081e581392838008eb009222c7692981ff4634
1 parent
b45f88e17f
Exists in
master
pretty print json
Showing
1 changed file
with
18 additions
and
1 deletions
Show diff stats
main.go
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 |