Blame view

main.go 4.81 KB
a99c98307   Marko Tikvić   first commit
1
2
3
  package gologger
  
  import (
a7081e581   Marko Tikvić   pretty print json
4
5
  	"bytes"
  	"encoding/json"
a99c98307   Marko Tikvić   first commit
6
  	"fmt"
df74f4a7e   Marko Tikvić   new filename format
7
  	"net/http"
cccb4b47c   Marko Tikvić   log http response
8
  	"net/http/httputil"
a99c98307   Marko Tikvić   first commit
9
  	"os"
e025a8738   Marko Tikvić   platform agnostic...
10
  	"path/filepath"
98708cdaf   Marko Tikvić   new version, does...
11
  	"runtime"
aa60a45ee   Marko Tikvić   changed log file ...
12
  	"strings"
3ba7b5695   Marko Tikvić   added mutex locks...
13
  	"sync"
baa4468b7   Marko Tikvić   Comments go befor...
14
  	"time"
a99c98307   Marko Tikvić   first commit
15
  )
b45f88e17   Marko Tikvić   more readable dat...
16
  const dateTimeFormat = "2006-01-02 15:04:05"
92485819d   Marko Tikvić   lint
17
  // Block ...
434e7da25   Marko Tikvić   changed initializ...
18
19
20
21
22
23
  const (
  	MaxLogSize5MB   int64 = 5 * 1024 * 1024
  	MaxLogSize1MB   int64 = 1 * 1024 * 1024
  	MaxLogSize500KB int64 = 500 * 1024
  	MaxLogSize100KB int64 = 100 * 1024
  	MaxLogSize512B  int64 = 512
98cf2ceeb   Marko Tikvić   new interaface; a...
24
  	logDirName            = "log"
434e7da25   Marko Tikvić   changed initializ...
25
  )
a99c98307   Marko Tikvić   first commit
26

92485819d   Marko Tikvić   lint
27
  // Logger ...
5eaa49d2a   Marko Tikvić   new design; allow...
28
  type Logger struct {
98cf2ceeb   Marko Tikvić   new interaface; a...
29
30
  	mu         *sync.Mutex
  	outputFile *os.File
23ce66f0f   Marko Tikvić   optional init par...
31

98cf2ceeb   Marko Tikvić   new interaface; a...
32
  	outputFileName string
3e936a3c2   Marko Tikvić   output file name ...
33
  	fullName       string
98cf2ceeb   Marko Tikvić   new interaface; a...
34
  	maxFileSize    int64
df74f4a7e   Marko Tikvić   new filename format
35
36
  
  	splitCount int
a99c98307   Marko Tikvić   first commit
37
  }
92485819d   Marko Tikvić   lint
38
  // New ...
98cf2ceeb   Marko Tikvić   new interaface; a...
39
  func New(name string, maxFileSize int64) (logger *Logger, err error) {
5eaa49d2a   Marko Tikvić   new design; allow...
40
  	logger = &Logger{}
23ce66f0f   Marko Tikvić   optional init par...
41

b45f88e17   Marko Tikvić   more readable dat...
42
  	logger.outputFileName = name
98cf2ceeb   Marko Tikvić   new interaface; a...
43
44
  	logger.mu = &sync.Mutex{}
  	logger.maxFileSize = maxFileSize
a99c98307   Marko Tikvić   first commit
45

98cf2ceeb   Marko Tikvić   new interaface; a...
46
47
48
  	err = os.Mkdir(logDirName, os.ModePerm)
  	if err != nil {
  		if !os.IsExist(err) {
b45f88e17   Marko Tikvić   more readable dat...
49
50
  			fmt.Fprintf(os.Stderr, "gologger: couldn't create event log directory: %s
  ", err.Error())
5eaa49d2a   Marko Tikvić   new design; allow...
51
  			return nil, err
a99c98307   Marko Tikvić   first commit
52
53
  		}
  	}
b45f88e17   Marko Tikvić   more readable dat...
54
55
  	date := strings.Replace(time.Now().Format(dateTimeFormat), ":", ".", -1)
  	logger.outputFileName += " " + date
3e936a3c2   Marko Tikvić   output file name ...
56
57
  	logger.fullName = logger.outputFileName + ".txt"
  	path := filepath.Join(logDirName, logger.fullName)
98cf2ceeb   Marko Tikvić   new interaface; a...
58
59
  	logger.outputFile, err = os.Create(path)
  	if err != nil {
b45f88e17   Marko Tikvić   more readable dat...
60
61
  		fmt.Fprintf(os.Stderr, "gologger: couldn't create event log file: %s
  ", err.Error())
98cf2ceeb   Marko Tikvić   new interaface; a...
62
  		return nil, err
e025a8738   Marko Tikvić   platform agnostic...
63
  	}
5eaa49d2a   Marko Tikvić   new design; allow...
64
  	return logger, nil
98708cdaf   Marko Tikvić   new version, does...
65
  }
92485819d   Marko Tikvić   lint
66
  // Log ...
df74f4a7e   Marko Tikvić   new filename format
67
  func (l *Logger) Log(format string, v ...interface{}) {
372beaf62   Marko Tikvić   refactored if sta...
68
69
70
71
72
73
74
75
  	if l.outputFile == nil {
  		return
  	}
  
  	l.mu.Lock()
  	defer l.mu.Unlock()
  
  	msg := fmt.Sprintf(format, v...)
b45f88e17   Marko Tikvić   more readable dat...
76
77
  	s := time.Now().Format(dateTimeFormat) + ": " + msg + "
  "
372beaf62   Marko Tikvić   refactored if sta...
78
79
  	if l.shouldSplit(len(s)) {
  		l.split()
23ce66f0f   Marko Tikvić   optional init par...
80
  	}
372beaf62   Marko Tikvić   refactored if sta...
81
  	l.outputFile.WriteString(s)
98708cdaf   Marko Tikvić   new version, does...
82
  }
92485819d   Marko Tikvić   lint
83
84
85
  // Print ...
  func (l *Logger) Print(format string, v ...interface{}) {
  	msg := fmt.Sprintf(format, v...)
b45f88e17   Marko Tikvić   more readable dat...
86
87
  	fmt.Printf("%s: %s
  ", time.Now().Format(dateTimeFormat), msg)
92485819d   Marko Tikvić   lint
88
89
90
91
92
93
94
  }
  
  // PrintTrace ...
  func (l *Logger) PrintTrace(format string, v ...interface{}) {
  	_, file, line, _ := runtime.Caller(1)
  
  	msg := fmt.Sprintf(format, v...)
b45f88e17   Marko Tikvić   more readable dat...
95
96
  	fmt.Printf("%s: %s %d: %s
  ", time.Now().Format(dateTimeFormat), file, line, msg)
92485819d   Marko Tikvić   lint
97
98
99
100
101
102
103
104
105
106
107
108
109
  }
  
  // Trace ...
  func (l *Logger) Trace(format string, v ...interface{}) {
  	if l.outputFile == nil {
  		return
  	}
  
  	l.mu.Lock()
  	defer l.mu.Unlock()
  
  	_, file, line, _ := runtime.Caller(1)
  	msg := fmt.Sprintf(format, v...)
b45f88e17   Marko Tikvić   more readable dat...
110
111
  	s := fmt.Sprintf("%s: %s %d: %s
  ", time.Now().Format(dateTimeFormat), file, line, msg)
92485819d   Marko Tikvić   lint
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  
  	if l.shouldSplit(len(s)) {
  		l.split()
  	}
  	l.outputFile.WriteString(s)
  }
  
  // PrintAndTrace ...
  func (l *Logger) PrintAndTrace(format string, v ...interface{}) {
  	l.Print(format, v)
  	l.Trace(format, v)
  }
  
  // LogHTTPRequest ...
093191eb2   Marko Tikvić   much cleaner, muc...
126
  func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string {
1f7fbc601   Marko Tikvić   logging user ID
127
128
  	if userID == "" {
  		userID = "-"
372beaf62   Marko Tikvić   refactored if sta...
129
  	}
df74f4a7e   Marko Tikvić   new filename format
130

372beaf62   Marko Tikvić   refactored if sta...
131
  	var b strings.Builder
093191eb2   Marko Tikvić   much cleaner, muc...
132

372beaf62   Marko Tikvić   refactored if sta...
133
134
135
  	b.WriteString("Request:
  ")
  	// CLF-like header
b45f88e17   Marko Tikvić   more readable dat...
136
137
  	fmt.Fprintf(&b, "%s %s %s
  ", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat))
cccb4b47c   Marko Tikvić   log http response
138

093191eb2   Marko Tikvić   much cleaner, muc...
139
140
141
142
  	body, err := httputil.DumpRequest(req, true)
  	if err != nil {
  		fmt.Fprintf(os.Stderr, "%v
  ", err)
cccb4b47c   Marko Tikvić   log http response
143
  	}
a7081e581   Marko Tikvić   pretty print json
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  
  	const sepStr = "\r
  \r
  "
  	sepIndex := bytes.Index(body, []byte(sepStr))
  	if sepIndex == -1 {
  		b.WriteString(string(body) + "
  
  ")
  	} else {
  		sepIndex += len(sepStr)
  		payload, _ := printJSON(body[sepIndex:])
  		b.WriteString(string(body[:sepIndex]) + string(payload) + "
  
  ")
  	}
372beaf62   Marko Tikvić   refactored if sta...
160

093191eb2   Marko Tikvić   much cleaner, muc...
161
162
  	return b.String()
  }
372beaf62   Marko Tikvić   refactored if sta...
163

feba66094   Marko Tikvić   split line constant
164
  const splitLine = "=============================================================="
92485819d   Marko Tikvić   lint
165
  // LogHTTPResponse ...
093191eb2   Marko Tikvić   much cleaner, muc...
166
  func (l *Logger) LogHTTPResponse(status int, duration time.Duration, size int) string {
feba66094   Marko Tikvić   split line constant
167
168
169
170
  	return fmt.Sprintf("Response:
  %d %v %dB
  %s
  ", status, duration, size, splitLine)
cccb4b47c   Marko Tikvić   log http response
171
  }
92485819d   Marko Tikvić   lint
172
  // CombineHTTPLogs ...
093191eb2   Marko Tikvić   much cleaner, muc...
173
  func (l *Logger) CombineHTTPLogs(in string, out string) {
372beaf62   Marko Tikvić   refactored if sta...
174
175
176
  	if l.outputFile == nil {
  		return
  	}
df74f4a7e   Marko Tikvić   new filename format
177

372beaf62   Marko Tikvić   refactored if sta...
178
179
  	l.mu.Lock()
  	defer l.mu.Unlock()
093191eb2   Marko Tikvić   much cleaner, muc...
180
  	msg := in + out
372beaf62   Marko Tikvić   refactored if sta...
181
182
  	if l.shouldSplit(len(msg)) {
  		l.split()
98708cdaf   Marko Tikvić   new version, does...
183
  	}
372beaf62   Marko Tikvić   refactored if sta...
184
  	l.outputFile.WriteString(msg)
98708cdaf   Marko Tikvić   new version, does...
185
  }
92485819d   Marko Tikvić   lint
186
  // Close ...
df74f4a7e   Marko Tikvić   new filename format
187
  func (l *Logger) Close() {
372beaf62   Marko Tikvić   refactored if sta...
188
189
190
191
192
193
  	if l.outputFile == nil {
  		return
  	}
  
  	err := l.outputFile.Close()
  	if err != nil {
b45f88e17   Marko Tikvić   more readable dat...
194
195
  		fmt.Fprintf(os.Stderr, "gologger: couldn't close event log file: %s
  ", err.Error())
a99c98307   Marko Tikvić   first commit
196
  	}
a99c98307   Marko Tikvić   first commit
197
  }
98cf2ceeb   Marko Tikvić   new interaface; a...
198
  func (l *Logger) split() {
372beaf62   Marko Tikvić   refactored if sta...
199
200
201
  	if l.outputFile == nil {
  		return
  	}
98cf2ceeb   Marko Tikvić   new interaface; a...
202
203
204
  	// close old file
  	err := l.outputFile.Close()
  	if err != nil {
b45f88e17   Marko Tikvić   more readable dat...
205
206
  		fmt.Fprintf(os.Stderr, "gologger: split: couldn't close event file
  ")
98cf2ceeb   Marko Tikvić   new interaface; a...
207
208
  		return
  	}
df74f4a7e   Marko Tikvić   new filename format
209
210
  
  	l.splitCount++
98cf2ceeb   Marko Tikvić   new interaface; a...
211
212
  	// open new file
  	var errnew error
3e936a3c2   Marko Tikvić   output file name ...
213
  	path := filepath.Join(logDirName, l.outputFileName+fmt.Sprintf("(%d)", l.splitCount)+".txt")
98cf2ceeb   Marko Tikvić   new interaface; a...
214
  	l.outputFile, errnew = os.Create(path)
a99c98307   Marko Tikvić   first commit
215

98cf2ceeb   Marko Tikvić   new interaface; a...
216
  	if errnew != nil {
b45f88e17   Marko Tikvić   more readable dat...
217
218
  		fmt.Fprintf(os.Stderr, "gologger: couldn't create new event log file: %s
  ", err.Error())
a99c98307   Marko Tikvić   first commit
219
220
  	}
  }
98cf2ceeb   Marko Tikvić   new interaface; a...
221
222
223
  func (l *Logger) shouldSplit(nextEntrySize int) bool {
  	stats, _ := l.outputFile.Stat()
  	return int64(nextEntrySize) >= (l.maxFileSize - stats.Size())
a99c98307   Marko Tikvić   first commit
224
  }
a7081e581   Marko Tikvić   pretty print json
225
226
227
228
229
230
  
  func printJSON(in []byte) (out []byte, err error) {
  	var buf bytes.Buffer
  	err = json.Indent(&buf, in, "", "    ")
  	return buf.Bytes(), err
  }