Skip to content

Commit 03f4c7d

Browse files
rybitsgirones
authored andcommitted
simplify logger to use request tracer
1 parent 54f02da commit 03f4c7d

File tree

7 files changed

+210
-74
lines changed

7 files changed

+210
-74
lines changed

tracing/config.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package tracing
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/opentracing/opentracing-go"
7+
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer"
8+
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
9+
)
10+
11+
const (
12+
HeaderNFDebugLogging = "X-NF-Debug-Logging"
13+
HeaderRequestUUID = "X-BB-CLIENT-REQUEST-UUID"
14+
)
15+
16+
type Config struct {
17+
Enabled bool `default:"false"`
18+
Host string `default:"localhost"`
19+
Port string `default:"8126"`
20+
Tags map[string]string
21+
}
22+
23+
func Configure(tc *Config, svcName string) {
24+
var t opentracing.Tracer = opentracing.NoopTracer{}
25+
if tc.Enabled {
26+
tracerAddr := fmt.Sprintf("%s:%s", tc.Host, tc.Port)
27+
tracerOps := []tracer.StartOption{
28+
tracer.WithServiceName(svcName),
29+
tracer.WithAgentAddr(tracerAddr),
30+
}
31+
32+
for k, v := range tc.Tags {
33+
tracerOps = append(tracerOps, tracer.WithGlobalTag(k, v))
34+
}
35+
36+
t = opentracer.New(tracerOps...)
37+
}
38+
opentracing.SetGlobalTracer(t)
39+
}

tracing/context.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package tracing
2+
3+
import (
4+
"context"
5+
"net/http"
6+
)
7+
8+
type contextKey string
9+
10+
const tracerKey = contextKey("nf-tracer-key")
11+
12+
func WrapWithTracer(r *http.Request, rt *RequestTracer) *http.Request {
13+
return r.WithContext(context.WithValue(r.Context(), tracerKey, rt))
14+
}
15+
16+
func GetTracer(r *http.Request) *RequestTracer {
17+
val := r.Context().Value(tracerKey)
18+
if val == nil {
19+
return nil
20+
}
21+
entry, ok := val.(*RequestTracer)
22+
if ok {
23+
return entry
24+
}
25+
return nil
26+
}

tracing/logging.go

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,61 @@ import (
88

99
const (
1010
logKey = contextKey("nf-log-key")
11-
12-
HeaderNFDebugLogging = "X-NF-Debug-Logging"
1311
)
1412

15-
type structuredLoggerEntry struct {
16-
Logger logrus.FieldLogger
17-
}
13+
func requestLogger(r *http.Request, log logrus.FieldLogger) logrus.FieldLogger {
14+
if r.Header.Get(HeaderNFDebugLogging) != "" {
15+
logger := logrus.New()
16+
logger.SetLevel(logrus.DebugLevel)
1817

19-
func getEntry(r *http.Request) *structuredLoggerEntry {
20-
val := r.Context().Value(logKey)
21-
if val == nil {
22-
return nil
23-
}
24-
entry, ok := val.(*structuredLoggerEntry)
25-
if ok {
26-
return entry
18+
if entry, ok := log.(*logrus.Entry); ok {
19+
log = logger.WithFields(entry.Data)
20+
}
2721
}
28-
return nil
22+
23+
reqID := RequestID(r)
24+
25+
log = log.WithFields(logrus.Fields{
26+
"request_id": reqID,
27+
})
28+
return log
2929
}
3030

3131
func GetLogger(r *http.Request) logrus.FieldLogger {
32-
entry := getEntry(r)
32+
entry := GetTracer(r)
3333
if entry == nil {
3434
return logrus.NewEntry(logrus.StandardLogger())
3535
}
36-
return entry.Logger
36+
return entry.FieldLogger
3737
}
3838

39+
// SetLogField will add the field to this log line and every one following
3940
func SetLogField(r *http.Request, key string, value interface{}) logrus.FieldLogger {
40-
entry := getEntry(r)
41+
entry := GetTracer(r)
4142
if entry == nil {
4243
return logrus.StandardLogger().WithField(key, value)
4344
}
44-
45-
entry.Logger = entry.Logger.WithField(key, value)
46-
return entry.Logger
45+
return entry.SetLogField(key, value)
4746
}
4847

48+
// SetLogFields will add the fields to this log line and every one following
4949
func SetLogFields(r *http.Request, fields logrus.Fields) logrus.FieldLogger {
50-
entry := getEntry(r)
50+
entry := GetTracer(r)
5151
if entry == nil {
5252
return logrus.StandardLogger().WithFields(fields)
5353
}
5454

55-
entry.Logger = entry.Logger.WithFields(fields)
56-
return entry.Logger
55+
return entry.SetLogFields(fields)
56+
}
57+
58+
// SetFinalField will add a field to the canonical line created at in Finish. It will add
59+
// it to this line, but not every log line in between
60+
func SetFinalField(r *http.Request, key string, value interface{}) logrus.FieldLogger {
61+
entry := GetTracer(r)
62+
if entry == nil {
63+
return logrus.StandardLogger().WithField(key, value)
64+
}
65+
66+
entry.FinalFields[key] = value
67+
return entry.FieldLogger.WithField(key, value)
5768
}

tracing/req_tracer.go

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,80 @@ import (
1010

1111
type RequestTracer struct {
1212
*trackingWriter
13-
RequestID string
13+
logrus.FieldLogger
1414

15-
request *http.Request
16-
span opentracing.Span
17-
start time.Time
15+
RequestID string
16+
FinalFields map[string]interface{}
17+
18+
remoteAddr string
19+
method string
20+
originalURL string
21+
referrer string
22+
span opentracing.Span
23+
start time.Time
1824
}
1925

2026
func NewTracer(w http.ResponseWriter, r *http.Request, log logrus.FieldLogger, service string) (http.ResponseWriter, *http.Request, *RequestTracer) {
2127
reqID := RequestID(r)
22-
23-
r, log = WrapWithLogger(r, reqID, log)
28+
log = requestLogger(r, log)
2429
r, span := WrapWithSpan(r, reqID, service)
2530
trackWriter := &trackingWriter{
2631
writer: w,
2732
log: log,
2833
}
2934

3035
rt := &RequestTracer{
36+
originalURL: r.URL.String(),
37+
method: r.Method,
38+
referrer: r.Referer(),
39+
remoteAddr: r.RemoteAddr,
40+
3141
RequestID: reqID,
3242
span: span,
3343
trackingWriter: trackWriter,
34-
request: r,
44+
FieldLogger: log,
45+
FinalFields: make(map[string]interface{}),
3546
}
47+
r = WrapWithTracer(r, rt)
3648

3749
return rt, r, rt
3850
}
3951

4052
func (rt *RequestTracer) Start() {
4153
rt.start = time.Now()
42-
rt.Log().WithField("url", rt.request.URL.String()).Info("Starting Request")
54+
rt.WithFields(logrus.Fields{
55+
"method": rt.method,
56+
"remote_addr": rt.remoteAddr,
57+
"referer": rt.referrer,
58+
"url": rt.originalURL,
59+
}).Info("Starting Request")
4360
}
4461

4562
func (rt *RequestTracer) Finish() {
4663
dur := time.Since(rt.start)
47-
fields := logrus.Fields{
48-
"status_code": rt.trackingWriter.status,
49-
"rsp_bytes": rt.trackingWriter.rspBytes,
50-
"dur": dur.String(),
51-
"dur_ns": dur.Nanoseconds(),
64+
65+
fields := logrus.Fields{}
66+
for k, v := range rt.FinalFields {
67+
fields[k] = v
5268
}
53-
rt.span.Finish()
54-
rt.Log().WithFields(fields).Info("Completed Request")
55-
}
5669

57-
func (rt *RequestTracer) Log() logrus.FieldLogger {
58-
return GetLogger(rt.request)
70+
fields["status_code"] = rt.trackingWriter.status
71+
fields["rsp_bytes"] = rt.trackingWriter.rspBytes
72+
fields["url"] = rt.originalURL
73+
fields["method"] = rt.method
74+
fields["dur"] = dur.String()
75+
fields["dur_ns"] = dur.Nanoseconds()
76+
77+
rt.span.Finish()
78+
rt.WithFields(fields).Info("Completed Request")
5979
}
6080

6181
func (rt *RequestTracer) SetLogField(key string, value interface{}) logrus.FieldLogger {
62-
return SetLogField(rt.request, key, value)
82+
rt.FieldLogger = rt.FieldLogger.WithField(key, value)
83+
return rt.FieldLogger
6384
}
6485

6586
func (rt *RequestTracer) SetLogFields(fields logrus.Fields) logrus.FieldLogger {
66-
return SetLogFields(rt.request, fields)
87+
rt.FieldLogger = rt.FieldLogger.WithFields(fields)
88+
return rt.FieldLogger
6789
}

tracing/req_tracer_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package tracing
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
logtest "github.com/sirupsen/logrus/hooks/test"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestTracerLogging(t *testing.T) {
14+
// func NewTracer(w http.ResponseWriter, r *http.Request, log logrus.FieldLogger, service string) (http.ResponseWriter, *http.Request, *RequestTracer) {
15+
rec := httptest.NewRecorder()
16+
req := httptest.NewRequest(http.MethodGet, "http://whatever.com/something", nil)
17+
18+
log, hook := logtest.NewNullLogger()
19+
20+
_, r, rt := NewTracer(rec, req, log, t.Name())
21+
22+
rt.Start()
23+
e := hook.LastEntry()
24+
assert.Equal(t, 5, len(e.Data))
25+
assert.NotEmpty(t, e.Data["request_id"])
26+
assert.NotEmpty(t, e.Data["remote_addr"])
27+
assert.Empty(t, e.Data["referrer"])
28+
assert.NotEmpty(t, e.Data["method"])
29+
assert.Equal(t, "http://whatever.com/something", e.Data["url"])
30+
fmt.Println(e.Data)
31+
32+
_ = SetLogField(r, "first", "second")
33+
SetFinalField(r, "final", "line").Info("should have the final here")
34+
e = hook.LastEntry()
35+
assert.Equal(t, 3, len(e.Data))
36+
assert.NotEmpty(t, e.Data["request_id"])
37+
assert.Equal(t, "line", e.Data["final"])
38+
assert.Equal(t, "second", e.Data["first"])
39+
fmt.Println(e.Data)
40+
41+
rt.Info("Shouldn't have the final line")
42+
e = hook.LastEntry()
43+
assert.Equal(t, 2, len(e.Data))
44+
assert.NotEmpty(t, e.Data["request_id"])
45+
assert.Equal(t, "second", e.Data["first"])
46+
fmt.Println(e.Data)
47+
48+
rt.WriteHeader(http.StatusOK)
49+
rt.Write([]byte{0, 1, 2, 3})
50+
rt.Finish()
51+
e = hook.LastEntry()
52+
53+
assert.Equal(t, 9, len(e.Data))
54+
55+
// the automatic fields
56+
assert.NotEmpty(t, e.Data["dur"])
57+
assert.NotEmpty(t, e.Data["dur_ns"])
58+
assert.NotEmpty(t, e.Data["request_id"])
59+
assert.Equal(t, 4, e.Data["rsp_bytes"])
60+
assert.Equal(t, 200, e.Data["status_code"])
61+
assert.Equal(t, "http://whatever.com/something", e.Data["url"])
62+
assert.Equal(t, "GET", e.Data["method"])
63+
64+
// the value that we added above
65+
assert.Equal(t, "second", e.Data["first"])
66+
assert.Equal(t, "line", e.Data["final"])
67+
}

tracing/tracer.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package tracing
22

33
import (
4-
"context"
54
"net/http"
65
"strconv"
76

@@ -13,12 +12,6 @@ import (
1312
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer"
1413
)
1514

16-
type contextKey string
17-
18-
const (
19-
HeaderRequestUUID = "X-BB-CLIENT-REQUEST-UUID"
20-
)
21-
2215
func TrackRequest(w http.ResponseWriter, r *http.Request, log logrus.FieldLogger, service string, next http.Handler) {
2316
w, r, rt := NewTracer(w, r, log, service)
2417
rt.Start()
@@ -35,30 +28,6 @@ func RequestID(r *http.Request) string {
3528
return id
3629
}
3730

38-
func WrapWithLogger(r *http.Request, reqID string, log logrus.FieldLogger) (*http.Request, logrus.FieldLogger) {
39-
if r.Header.Get(HeaderNFDebugLogging) != "" {
40-
logger := logrus.New()
41-
logger.SetLevel(logrus.DebugLevel)
42-
43-
if entry, ok := log.(*logrus.Entry); ok {
44-
log = logger.WithFields(entry.Data)
45-
}
46-
}
47-
48-
log = log.WithFields(logrus.Fields{
49-
"method": r.Method,
50-
"path": r.URL.Path,
51-
"remote_addr": r.RemoteAddr,
52-
"referer": r.Referer(),
53-
"request_id": reqID,
54-
})
55-
56-
entry := &structuredLoggerEntry{log}
57-
r = r.WithContext(context.WithValue(r.Context(), logKey, entry))
58-
59-
return r, log
60-
}
61-
6231
func WrapWithSpan(r *http.Request, reqID, service string) (*http.Request, opentracing.Span) {
6332
span := opentracing.SpanFromContext(r.Context())
6433
if span != nil {

tracing/writer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/sirupsen/logrus"
1010
)
1111

12+
var _ http.Hijacker = (*trackingWriter)(nil)
13+
1214
type trackingWriter struct {
1315
writer http.ResponseWriter
1416
rspBytes int

0 commit comments

Comments
 (0)