Commit 829723543a62ad2f902bc9fcfedc71edab077f0b
1 parent
03121daf9b
Exists in
master
Improved tracing. Split tracing and HTTP logging in separate files.
Showing
3 changed files
with
144 additions
and
88 deletions
Show diff stats
http_logs.go
... | ... | @@ -0,0 +1,64 @@ |
1 | +package gologger | |
2 | + | |
3 | +import ( | |
4 | + "bytes" | |
5 | + "fmt" | |
6 | + "net/http" | |
7 | + "net/http/httputil" | |
8 | + "os" | |
9 | + "strings" | |
10 | + "time" | |
11 | +) | |
12 | + | |
13 | +// LogHTTPRequest ... | |
14 | +func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string { | |
15 | + if userID == "" { | |
16 | + userID = "-" | |
17 | + } | |
18 | + | |
19 | + var b strings.Builder | |
20 | + | |
21 | + b.WriteString("Request:\n") | |
22 | + // CLF-like header | |
23 | + fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat)) | |
24 | + | |
25 | + body, err := httputil.DumpRequest(req, true) | |
26 | + if err != nil { | |
27 | + fmt.Fprintf(os.Stderr, "%v\n", err) | |
28 | + } | |
29 | + | |
30 | + const sepStr = "\r\n\r\n" | |
31 | + sepIndex := bytes.Index(body, []byte(sepStr)) | |
32 | + if sepIndex == -1 { | |
33 | + b.WriteString(string(body) + "\n\n") | |
34 | + } else { | |
35 | + sepIndex += len(sepStr) | |
36 | + payload, _ := printJSON(body[sepIndex:]) | |
37 | + b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n") | |
38 | + } | |
39 | + | |
40 | + return b.String() | |
41 | +} | |
42 | + | |
43 | +const splitLine = "==============================================================" | |
44 | + | |
45 | +// LogHTTPResponse ... | |
46 | +func (l *Logger) LogHTTPResponse(status int, duration time.Duration, size int) string { | |
47 | + return fmt.Sprintf("Response:\n%d %v %dB\n%s\n", status, duration, size, splitLine) | |
48 | +} | |
49 | + | |
50 | +// CombineHTTPLogs ... | |
51 | +func (l *Logger) CombineHTTPLogs(in string, out string) { | |
52 | + if l.outputFile == nil { | |
53 | + return | |
54 | + } | |
55 | + | |
56 | + l.mu.Lock() | |
57 | + defer l.mu.Unlock() | |
58 | + | |
59 | + msg := in + out | |
60 | + if l.shouldSplit(len(msg)) { | |
61 | + l.split() | |
62 | + } | |
63 | + l.outputFile.WriteString(msg) | |
64 | +} | ... | ... |
main.go
... | ... | @@ -4,17 +4,15 @@ import ( |
4 | 4 | "bytes" |
5 | 5 | "encoding/json" |
6 | 6 | "fmt" |
7 | - "net/http" | |
8 | - "net/http/httputil" | |
9 | 7 | "os" |
10 | 8 | "path/filepath" |
11 | - "runtime" | |
12 | 9 | "strings" |
13 | 10 | "sync" |
14 | 11 | "time" |
15 | 12 | ) |
16 | 13 | |
17 | 14 | const dateTimeFormat = "2006-01-02 15:04:05" |
15 | +const thisFile = "" | |
18 | 16 | |
19 | 17 | // Block ... |
20 | 18 | const ( |
... | ... | @@ -89,111 +87,35 @@ func (l *Logger) Print(format string, v ...interface{}) { |
89 | 87 | fmt.Printf("%s: %s\n", time.Now().Format(dateTimeFormat), msg) |
90 | 88 | } |
91 | 89 | |
92 | -const MaxStackDepth = 10000 | |
93 | - | |
94 | -// CallStack | |
95 | -func CallStack() (stack string) { | |
96 | - callers := make([]uintptr, MaxStackDepth) // min 1 | |
97 | - stackDepth := runtime.Callers(2, callers) | |
98 | - frames := runtime.CallersFrames(callers) | |
99 | - | |
100 | - for i := 0; i < stackDepth; i++ { | |
101 | - if i >= 2 { // skip runtime and startup | |
102 | - frame, next := frames.Next() | |
103 | - stack += fmt.Sprintf("[%s %d]\n", frame.File, frame.Line) | |
104 | - if !next { | |
105 | - break | |
106 | - } | |
107 | - } | |
108 | - } | |
109 | - | |
110 | - return | |
111 | -} | |
112 | - | |
113 | 90 | // PrintTrace ... |
114 | 91 | func (l *Logger) PrintTrace(format string, v ...interface{}) { |
115 | - stack := CallStack() | |
116 | - msg := fmt.Sprintf(format, v...) | |
117 | - fmt.Printf("%s:\n%s\n%s\n", time.Now().Format(dateTimeFormat), stack, msg) | |
92 | + s := getTrace(format, v...) | |
93 | + fmt.Printf("%s", s) | |
118 | 94 | } |
119 | 95 | |
120 | 96 | // Trace ... |
121 | -func (l *Logger) Trace(format string, v ...interface{}) { | |
97 | +func (l *Logger) Trace(format string, v ...interface{}) string { | |
122 | 98 | if l.outputFile == nil { |
123 | - return | |
99 | + return "" | |
124 | 100 | } |
125 | 101 | |
126 | 102 | l.mu.Lock() |
127 | 103 | defer l.mu.Unlock() |
128 | 104 | |
129 | - stack := CallStack() | |
130 | - | |
131 | - msg := fmt.Sprintf(format, v...) | |
132 | - s := fmt.Sprintf("%s:\n%s\n%s\n\n", time.Now().Format(dateTimeFormat), stack, msg) | |
105 | + s := getTrace(format, v...) | |
133 | 106 | |
134 | 107 | if l.shouldSplit(len(s)) { |
135 | 108 | l.split() |
136 | 109 | } |
137 | 110 | l.outputFile.WriteString(s) |
111 | + | |
112 | + return s | |
138 | 113 | } |
139 | 114 | |
140 | 115 | // PrintAndTrace ... |
141 | 116 | func (l *Logger) PrintAndTrace(format string, v ...interface{}) { |
142 | - l.Print(format, v...) | |
143 | - l.Trace(format, v...) | |
144 | -} | |
145 | - | |
146 | -// LogHTTPRequest ... | |
147 | -func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string { | |
148 | - if userID == "" { | |
149 | - userID = "-" | |
150 | - } | |
151 | - | |
152 | - var b strings.Builder | |
153 | - | |
154 | - b.WriteString("Request:\n") | |
155 | - // CLF-like header | |
156 | - fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat)) | |
157 | - | |
158 | - body, err := httputil.DumpRequest(req, true) | |
159 | - if err != nil { | |
160 | - fmt.Fprintf(os.Stderr, "%v\n", err) | |
161 | - } | |
162 | - | |
163 | - const sepStr = "\r\n\r\n" | |
164 | - sepIndex := bytes.Index(body, []byte(sepStr)) | |
165 | - if sepIndex == -1 { | |
166 | - b.WriteString(string(body) + "\n\n") | |
167 | - } else { | |
168 | - sepIndex += len(sepStr) | |
169 | - payload, _ := printJSON(body[sepIndex:]) | |
170 | - b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n") | |
171 | - } | |
172 | - | |
173 | - return b.String() | |
174 | -} | |
175 | - | |
176 | -const splitLine = "==============================================================" | |
177 | - | |
178 | -// LogHTTPResponse ... | |
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) | |
181 | -} | |
182 | - | |
183 | -// CombineHTTPLogs ... | |
184 | -func (l *Logger) CombineHTTPLogs(in string, out string) { | |
185 | - if l.outputFile == nil { | |
186 | - return | |
187 | - } | |
188 | - | |
189 | - l.mu.Lock() | |
190 | - defer l.mu.Unlock() | |
191 | - | |
192 | - msg := in + out | |
193 | - if l.shouldSplit(len(msg)) { | |
194 | - l.split() | |
195 | - } | |
196 | - l.outputFile.WriteString(msg) | |
117 | + t := l.Trace(format, v...) | |
118 | + fmt.Println(t) | |
197 | 119 | } |
198 | 120 | |
199 | 121 | // Close ... |
... | ... | @@ -234,3 +156,8 @@ func printJSON(in []byte) (out []byte, err error) { |
234 | 156 | err = json.Indent(&buf, in, "", " ") |
235 | 157 | return buf.Bytes(), err |
236 | 158 | } |
159 | + | |
160 | +// GetOutDir ... | |
161 | +func (l *Logger) GetOutDir() string { | |
162 | + return l.directory | |
163 | +} | ... | ... |
tracing.go
... | ... | @@ -0,0 +1,65 @@ |
1 | +package gologger | |
2 | + | |
3 | +import ( | |
4 | + "fmt" | |
5 | + "math" | |
6 | + "runtime" | |
7 | + "strings" | |
8 | + "time" | |
9 | +) | |
10 | + | |
11 | +// getCallStack | |
12 | +func getCallStack() (stack []string) { | |
13 | + const ( | |
14 | + maxStackDepth = 10000 | |
15 | + skipRuntime = 2 // skip runtime and startup | |
16 | + skipCallers = 2 | |
17 | + thisPackage = "gologger" | |
18 | + ) | |
19 | + | |
20 | + callers := make([]uintptr, maxStackDepth) // min 1 | |
21 | + | |
22 | + stackDepth := runtime.Callers(skipCallers, callers) | |
23 | + frames := runtime.CallersFrames(callers) | |
24 | + | |
25 | + for i := 0; i < skipRuntime; i++ { | |
26 | + frames.Next() | |
27 | + } | |
28 | + | |
29 | + for i := 0; i < stackDepth-skipRuntime-skipCallers; i++ { | |
30 | + frame, next := frames.Next() | |
31 | + if !strings.Contains(frame.File, thisPackage) { | |
32 | + stack = append(stack, fmt.Sprintf("[%s %d]", frame.File, frame.Line)) | |
33 | + } | |
34 | + if !next { | |
35 | + break | |
36 | + } | |
37 | + } | |
38 | + | |
39 | + reverseStack(stack) | |
40 | + | |
41 | + return stack | |
42 | +} | |
43 | + | |
44 | +// in place | |
45 | +func reverseStack(stack []string) { | |
46 | + middle := int(math.Floor(float64(len(stack)) / 2.0)) | |
47 | + | |
48 | + lastIndex := len(stack) - 1 | |
49 | + for i := 0; i < middle; i++ { | |
50 | + stack[i], stack[lastIndex] = stack[lastIndex], stack[i] | |
51 | + lastIndex-- | |
52 | + } | |
53 | +} | |
54 | + | |
55 | +func getTrace(format string, v ...interface{}) (t string) { | |
56 | + stack := getCallStack() | |
57 | + | |
58 | + t = time.Now().Format(dateTimeFormat) + ":\n" | |
59 | + for _, s := range stack { | |
60 | + t += s + "\n" | |
61 | + } | |
62 | + t += fmt.Sprintf(format, v...) + "\n" | |
63 | + | |
64 | + return t | |
65 | +} | ... | ... |