Skip to content

Commit

Permalink
contrib/valyala/fasthttp.v1: add a fasthttp integration to ddtrace (#…
Browse files Browse the repository at this point in the history
…2305)

Co-authored-by: Dario Castañé <dario.castane@datadoghq.com>
Co-authored-by: Rodrigo Argüello <rodrigo.arguello@datadoghq.com>
  • Loading branch information
3 people authored Dec 18, 2023
1 parent 7e72b4e commit ff5a05e
Show file tree
Hide file tree
Showing 8 changed files with 473 additions and 12 deletions.
12 changes: 6 additions & 6 deletions contrib/internal/fasthttptrace/fasthttpheaderscarrier.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ import (
"github.com/valyala/fasthttp"
)

// FastHTTPHeadersCarrier implements tracer.TextMapWriter and tracer.TextMapReader on top
// HTTPHeadersCarrier implements tracer.TextMapWriter and tracer.TextMapReader on top
// of fasthttp's RequestHeader object, allowing it to be used as a span context carrier for
// distributed tracing.
type FastHTTPHeadersCarrier struct {
type HTTPHeadersCarrier struct {
ReqHeader *fasthttp.RequestHeader
}

var _ tracer.TextMapWriter = (*FastHTTPHeadersCarrier)(nil)
var _ tracer.TextMapReader = (*FastHTTPHeadersCarrier)(nil)
var _ tracer.TextMapWriter = (*HTTPHeadersCarrier)(nil)
var _ tracer.TextMapReader = (*HTTPHeadersCarrier)(nil)

// ForeachKey iterates over fasthttp request header keys and values
func (f *FastHTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error {
func (f *HTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error {
keys := f.ReqHeader.PeekKeys()
for _, key := range keys {
sKey := string(key)
Expand All @@ -36,6 +36,6 @@ func (f *FastHTTPHeadersCarrier) ForeachKey(handler func(key, val string) error)

// Set adds the given value to request header for key. Key will be lowercased to match
// the metadata implementation.
func (f *FastHTTPHeadersCarrier) Set(key, val string) {
func (f *HTTPHeadersCarrier) Set(key, val string) {
f.ReqHeader.Set(key, val)
}
10 changes: 5 additions & 5 deletions contrib/internal/fasthttptrace/fasthttpheaderscarrier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import (
"github.com/valyala/fasthttp"
)

func TestFastHTTPHeadersCarrierSet(t *testing.T) {
func TestHTTPHeadersCarrierSet(t *testing.T) {
assert := assert.New(t)
fcc := &FastHTTPHeadersCarrier{
fcc := &HTTPHeadersCarrier{
ReqHeader: new(fasthttp.RequestHeader),
}
t.Run("key-val", func(t *testing.T) {
Expand Down Expand Up @@ -55,7 +55,7 @@ func TestFastHTTPHeadersCarrierSet(t *testing.T) {
})
}

func TestFastHTTPHeadersCarrierForeachKey(t *testing.T) {
func TestHTTPHeadersCarrierForeachKey(t *testing.T) {
assert := assert.New(t)
h := new(fasthttp.RequestHeader)
headers := map[string][]string{
Expand All @@ -68,7 +68,7 @@ func TestFastHTTPHeadersCarrierForeachKey(t *testing.T) {
h.Add(k, v)
}
}
fcc := &FastHTTPHeadersCarrier{
fcc := &HTTPHeadersCarrier{
ReqHeader: h,
}
err := fcc.ForeachKey(func(k, v string) error {
Expand All @@ -84,7 +84,7 @@ func TestInjectExtract(t *testing.T) {
mt := mocktracer.Start()
defer mt.Stop()
pspan, _ := tracer.StartSpanFromContext(context.Background(), "test")
fcc := &FastHTTPHeadersCarrier{
fcc := &HTTPHeadersCarrier{
ReqHeader: &fasthttp.RequestHeader{},
}
err := tracer.Inject(pspan.Context(), fcc)
Expand Down
37 changes: 37 additions & 0 deletions contrib/valyala/fasthttp.v1/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016 Datadog, Inc.

package fasthttp_test

import (
"fmt"

fasthttptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/valyala/fasthttp.v1"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"

"github.com/valyala/fasthttp"
)

func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
fmt.Fprintf(ctx, "Hello World!")
}

func Example() {
// Start the tracer
tracer.Start()
defer tracer.Stop()

// Start fasthttp server
fasthttp.ListenAndServe(":8081", fasthttptrace.WrapHandler(fastHTTPHandler))
}

func Example_withServiceName() {
// Start the tracer
tracer.Start()
defer tracer.Stop()

// Start fasthttp server
fasthttp.ListenAndServe(":8081", fasthttptrace.WrapHandler(fastHTTPHandler, fasthttptrace.WithServiceName("fasthttp-server")))
}
77 changes: 77 additions & 0 deletions contrib/valyala/fasthttp.v1/fasthttp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016 Datadog, Inc.

// Package fasthttp provides functions to trace the valyala/fasthttp package (https://github.com/valyala/fasthttp)
package fasthttp // import "gopkg.in/DataDog/dd-trace-go.v1/contrib/valyala/fasthttp.v1"

import (
"fmt"
"strconv"

"github.com/valyala/fasthttp"
"gopkg.in/DataDog/dd-trace-go.v1/contrib/internal/fasthttptrace"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/DataDog/dd-trace-go.v1/internal/log"
"gopkg.in/DataDog/dd-trace-go.v1/internal/telemetry"
)

const componentName = "valyala/fasthttp.v1"

func init() {
telemetry.LoadIntegration(componentName)
tracer.MarkIntegrationImported(componentName)
}

// WrapHandler wraps a fasthttp.RequestHandler with tracing middleware
func WrapHandler(h fasthttp.RequestHandler, opts ...Option) fasthttp.RequestHandler {
cfg := newConfig()
for _, fn := range opts {
fn(cfg)
}
log.Debug("contrib/valyala/fasthttp.v1: Configuring Middleware: cfg: %#v", cfg)
spanOpts := []tracer.StartSpanOption{
tracer.ServiceName(cfg.serviceName),
}
return func(fctx *fasthttp.RequestCtx) {
if cfg.ignoreRequest(fctx) {
h(fctx)
return
}
spanOpts = append(spanOpts, defaultSpanOptions(fctx)...)
fcc := &fasthttptrace.HTTPHeadersCarrier{
ReqHeader: &fctx.Request.Header,
}
if sctx, err := tracer.Extract(fcc); err == nil {
spanOpts = append(spanOpts, tracer.ChildOf(sctx))
}
span := fasthttptrace.StartSpanFromContext(fctx, "http.request", spanOpts...)
defer span.Finish()
h(fctx)
span.SetTag(ext.ResourceName, cfg.resourceNamer(fctx))
status := fctx.Response.StatusCode()
if cfg.isStatusError(status) {
span.SetTag(ext.Error, fmt.Errorf("%d: %s", status, string(fctx.Response.Body())))
}
span.SetTag(ext.HTTPCode, strconv.Itoa(status))
}
}

func defaultSpanOptions(fctx *fasthttp.RequestCtx) []tracer.StartSpanOption {
opts := []ddtrace.StartSpanOption{
tracer.Tag(ext.Component, componentName),
tracer.Tag(ext.SpanKind, ext.SpanKindServer),
tracer.SpanType(ext.SpanTypeWeb),
tracer.Tag(ext.HTTPMethod, string(fctx.Method())),
tracer.Tag(ext.HTTPURL, string(fctx.URI().FullURI())),
tracer.Tag(ext.HTTPUserAgent, string(fctx.UserAgent())),
tracer.Measured(),
}
if host := string(fctx.Host()); len(host) > 0 {
opts = append(opts, tracer.Tag("http.host", host))
}
return opts
}
Loading

0 comments on commit ff5a05e

Please sign in to comment.