Skip to content

Commit

Permalink
Ignore URL paths on Traced Handler (#13)
Browse files Browse the repository at this point in the history
* initial work done in http.go

* adding http_test.go

* refactor for PR

* adding feedback from PR
  • Loading branch information
jasonolmstead33 authored and andyday committed Aug 3, 2017
1 parent 6e0cfd6 commit afeff3e
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 2 deletions.
10 changes: 9 additions & 1 deletion http.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,15 @@ func TracedHTTPHandler(
interceptor ...TracedHTTPInterceptor,
) http.Handler {
mux, muxFound := h.(*http.ServeMux)

fn := func(w http.ResponseWriter, r *http.Request) {
for _, v := range interceptor {
config := v(r)
if config.Ignored != nil && config.Ignored.MatchString(r.URL.String()) {
h.ServeHTTP(w, r)
return
}
}

tracer := opentracing.GlobalTracer()
parentCtx, _ := tracer.Extract(core.HTTPHeaders, core.HTTPHeadersCarrier(r.Header))

Expand Down Expand Up @@ -236,6 +243,7 @@ func TracedHTTPHandler(

debug("TracedHttpHandler: ServeHTTP(...)")
h.ServeHTTP(&ri, r.WithContext(ContextWithSpan(r.Context(), span)))

}

return http.HandlerFunc(fn)
Expand Down
80 changes: 80 additions & 0 deletions http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"regexp"
"time"

ctrace "github.com/Nordstrom/ctrace-go"
Expand Down Expand Up @@ -168,6 +169,85 @@ var _ = Describe("http", func() {
})
})

Context("for ServeMux or ListenAndServe, ignored Paths", func() {
BeforeEach(func() {
mux.HandleFunc("/v1/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
})
mux.HandleFunc("/test/error", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(400)
w.Write([]byte("There was an error"))
})
mux.HandleFunc("/test/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
})
reg, _ := regexp.Compile(`(\/v1\/health)`)

inter := func(r *http.Request) ctrace.SpanConfig {
return ctrace.ConfigSpan("", reg)
}

th := ctrace.TracedHTTPHandler(mux, inter)
srv = httptest.NewServer(th)
})

AfterEach(func() {
srv.Close()
})

It("records success correctly", func() {
_, err := http.Get(srv.URL + "/test/foo")

Expect(err).ShouldNot(HaveOccurred())

sp := buf.Spans()[0]
Expect(sp.Operation).To(Equal("GET:/test/"))
Expect(sp.ParentID).To(BeEmpty())
Expect(sp.TraceID).ToNot(BeEmpty())
Expect(sp.SpanID).ToNot(BeEmpty())
Expect(sp.Start).To(BeNumerically(">=", start.UnixNano()/1000))
Expect(sp.Finish).To(BeNumerically(">=", sp.Start))
Expect(sp.Duration).To(BeNumerically(">=", sp.Finish-sp.Start-2))
Expect(sp.Duration).To(BeNumerically("<=", sp.Finish-sp.Start+2))

tags := sp.Tags

Expect(tags["span.kind"]).To(Equal("server"))
Expect(tags["component"]).To(Equal("ctrace.TracedHttpHandler"))
Expect(tags["http.url"]).To(Equal("/test/foo"))
Expect(tags["http.method"]).To(Equal("GET"))
Expect(tags["http.remote_addr"]).ShouldNot(BeEmpty())
Expect(tags["http.user_agent"]).To(Equal("Go-http-client/1.1"))
Expect(tags["http.status_code"]).To(Equal(float64(200)))
})

It("ignores health endpoints", func() {
_, err := http.Get(srv.URL + "/v1/health")

Expect(err).ShouldNot(HaveOccurred())

sp := buf.Spans()

Expect(len(sp)).To(Equal(0))
})

It("records error correctly", func() {
res, err := http.Get(srv.URL + "/test/error")

Expect(err).ShouldNot(HaveOccurred())
body, err := ioutil.ReadAll(res.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(string(body)).To(Equal("There was an error"))
Expect(res.StatusCode).To(Equal(400))

sp := buf.Spans()[0]
Expect(sp.Operation).To(Equal("GET:/test/error"))
tags := sp.Tags
Expect(tags["error"]).To(Equal(true))
Expect(tags["http.status_code"]).To(Equal(float64(400)))
})
})

Context("for Handle", func() {
It("records default OperationName", func() {
mux.Handle(
Expand Down
1 change: 1 addition & 0 deletions lambda_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var _ = Describe("TracedAPIGwLambdaProxyHandler", func() {
if evt.Path == "/intercept" {
return ctrace.ConfigSpan(
"newopname",
nil,
opentracing.Tag{Key: "mytag", Value: "myval"},
ext.HTTPMethod("POST"),
)
Expand Down
11 changes: 10 additions & 1 deletion span_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package ctrace

import opentracing "github.com/opentracing/opentracing-go"
import (
"regexp"

opentracing "github.com/opentracing/opentracing-go"
)

// SpanConfig is used by middleware interceptors to return custom OperationName
// and Tags
Expand All @@ -9,6 +13,9 @@ type SpanConfig struct {
// OperationName is the custom operation name decided by interceptor
OperationName string

// IgnoredPaths are URL paths ignored by tracer (ex.. /health to be ignored as it is used by a load balancer)
Ignored *regexp.Regexp

// Tags are the custom start span options decided by interceptor.
Tags []opentracing.StartSpanOption
}
Expand All @@ -27,10 +34,12 @@ type SpanConfig struct {
// )
func ConfigSpan(
operationName string,
ignored *regexp.Regexp,
tags ...opentracing.StartSpanOption,
) SpanConfig {
return SpanConfig{
OperationName: operationName,
Ignored: ignored,
Tags: tags,
}
}

0 comments on commit afeff3e

Please sign in to comment.