Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added possibility to customize span operationName #77

Merged
merged 2 commits into from
Jun 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions jaegertracing/jaegertracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ type (
// http body limit size (in bytes)
// NOTE: don't specify values larger than 60000 as jaeger can't handle values in span.LogKV larger than 60000 bytes
LimitSize int

// OperationNameFunc composes operation name based on context. Can be used to override default naming
OperationNameFunc func(c echo.Context) string
}
)

Expand All @@ -72,8 +75,9 @@ var (
ComponentName: defaultComponentName,
IsBodyDump: false,

LimitHTTPBody: true,
LimitSize: 60_000,
LimitHTTPBody: true,
LimitSize: 60_000,
OperationNameFunc: defaultOperationName,
}
)

Expand Down Expand Up @@ -130,6 +134,9 @@ func TraceWithConfig(config TraceConfig) echo.MiddlewareFunc {
if config.ComponentName == "" {
config.ComponentName = defaultComponentName
}
if config.OperationNameFunc == nil {
config.OperationNameFunc = defaultOperationName
}

return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
Expand All @@ -138,7 +145,7 @@ func TraceWithConfig(config TraceConfig) echo.MiddlewareFunc {
}

req := c.Request()
opname := "HTTP " + req.Method + " URL: " + c.Path()
opname := config.OperationNameFunc(c)
realIP := c.RealIP()
requestID := getRequestID(c) // request-id generated by reverse-proxy

Expand Down Expand Up @@ -218,10 +225,10 @@ func TraceWithConfig(config TraceConfig) echo.MiddlewareFunc {

func limitString(str string, size int) string {
if len(str) > size {
return str[:size/2] + "\n---- skipped ----\n" + str[len(str)-size/2:]
return str[:size/2] + "\n---- skipped ----\n" + str[len(str)-size/2:]
}

return str
return str
}

func logError(span opentracing.Span, err error) {
Expand All @@ -248,6 +255,11 @@ func generateToken() string {
return fmt.Sprintf("%x", b)
}

func defaultOperationName(c echo.Context) string {
req := c.Request()
return "HTTP " + req.Method + " URL: " + c.Path()
}

// TraceFunction wraps funtion with opentracing span adding tags for the function name and caller details
func TraceFunction(ctx echo.Context, fn interface{}, params ...interface{}) (result []reflect.Value) {
// Get function name
Expand Down
63 changes: 61 additions & 2 deletions jaegertracing/jaegertracing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/labstack/echo/v4"
Expand Down Expand Up @@ -101,11 +102,14 @@ func (tr *mockTracer) currentSpan() *mockSpan {
}

func (tr *mockTracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span {
tr.hasStartSpanWithOption = (len(opts) > 0)
tr.hasStartSpanWithOption = len(opts) > 0
if tr.span != nil {
tr.span.opName = operationName
return tr.span
}
return createSpan(tr)
span := createSpan(tr)
span.opName = operationName
return span
}

func (tr *mockTracer) Inject(sm opentracing.SpanContext, format interface{}, carrier interface{}) error {
Expand Down Expand Up @@ -325,3 +329,58 @@ func TestTraceWithoutLimitHTTPBody(t *testing.T) {
assert.Equal(t, "123456789012345678901234567890", tracer.currentSpan().getLog("http.req.body"))
assert.Equal(t, "Hi 123456789012345678901234567890", tracer.currentSpan().getLog("http.resp.body"))
}

func TestTraceWithDefaultOperationName(t *testing.T) {
tracer := createMockTracer()

e := echo.New()
e.Use(Trace(tracer))

e.GET("/trace", func(c echo.Context) error {
return c.String(http.StatusOK, "Hi")
})

req := httptest.NewRequest(http.MethodGet, "/trace", nil)
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)

assert.Equal(t, "HTTP GET URL: /trace", tracer.currentSpan().getOpName())
}

func TestTraceWithCustomOperationName(t *testing.T) {
tracer := createMockTracer()

e := echo.New()
e.Use(TraceWithConfig(TraceConfig{
Tracer: tracer,
ComponentName: "EchoTracer",
OperationNameFunc: func(c echo.Context) string {
// This is an example of operation name customization
// In most cases default formatting is more than enough
req := c.Request()
opName := "HTTP " + req.Method

path := c.Path()
paramNames := c.ParamNames()

for _, name := range paramNames {
from := ":" + name
to := "{" + name + "}"
path = strings.ReplaceAll(path, from, to)
}

return opName + " " + path
},
}))

e.GET("/trace/:traceID/spans/:spanID", func(c echo.Context) error {
return c.String(http.StatusOK, "Hi")
})

req := httptest.NewRequest(http.MethodGet, "/trace/123456/spans/123", nil)
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)

assert.Equal(t, true, tracer.currentSpan().isFinished())
assert.Equal(t, "HTTP GET /trace/{traceID}/spans/{spanID}", tracer.currentSpan().getOpName())
}