1// Unless explicitly stated otherwise all files in this repository are licensed
2// under the Apache License Version 2.0.
3// This product includes software developed at Datadog (https://www.datadoghq.com/).
4// Copyright 2016 Datadog, Inc.
5
6// Package fiber provides tracing functions for tracing the fiber package (https://github.com/gofiber/fiber).
7package fiber // import "gopkg.in/DataDog/dd-trace-go.v1/contrib/gofiber/fiber.v2"
8
9import (
10	"fmt"
11	"math"
12	"net/http"
13	"strconv"
14
15	"github.com/gofiber/fiber/v2"
16
17	"gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
18	"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
19	"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
20	"gopkg.in/DataDog/dd-trace-go.v1/internal/log"
21)
22
23// Middleware returns middleware that will trace incoming requests.
24func Middleware(opts ...Option) func(c *fiber.Ctx) error {
25	cfg := new(config)
26	defaults(cfg)
27	for _, fn := range opts {
28		fn(cfg)
29	}
30	log.Debug("gofiber/fiber.v2: Middleware: %#v", cfg)
31	return func(c *fiber.Ctx) error {
32		opts := []ddtrace.StartSpanOption{
33			tracer.SpanType(ext.SpanTypeWeb),
34			tracer.ServiceName(cfg.serviceName),
35			tracer.Tag(ext.HTTPMethod, c.Method()),
36			tracer.Tag(ext.HTTPURL, string(c.Request().URI().PathOriginal())),
37			tracer.Measured(),
38		}
39		if !math.IsNaN(cfg.analyticsRate) {
40			opts = append(opts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate))
41		}
42
43		opts = append(opts, cfg.spanOpts...)
44		span, _ := tracer.StartSpanFromContext(c.Context(), "http.request", opts...)
45
46		fmt.Printf("Starting Span")
47		defer span.Finish()
48
49		resourceName := c.Path()
50		if resourceName == "" {
51			resourceName = "unknown"
52		}
53		resourceName = c.Method() + " " + resourceName
54		span.SetTag(ext.ResourceName, resourceName)
55
56		// pass the execution down the line
57		err := c.Next()
58
59		status := c.Response().StatusCode()
60		// on the off chance we don't yet have a status after the rest of the things have run
61		if status == 0 {
62			// 0 - means we do not have a status code at this point
63			// in case the response was returned by a middleware without one
64			status = http.StatusOK
65		}
66		span.SetTag(ext.HTTPCode, strconv.Itoa(status))
67
68		if cfg.isStatusError(status) {
69			// mark 5xx server error
70			span.SetTag(ext.Error, fmt.Errorf("%d: %s", status, http.StatusText(status)))
71		}
72		return err
73	}
74}
75