Commit 829723543a62ad2f902bc9fcfedc71edab077f0b

Authored by Marko Tikvić
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
... ... @@ -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 +}
... ...
... ... @@ -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 +}
... ...
... ... @@ -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 +}
... ...